Skip to content

Fixing Selenium Session Not Created Error in Django

In a community I participate in, a developer recently ran into a wall while integrating end-to-end testing into their Django project. They were hitting a persistent SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version X error. This usually happens when the browser auto-updates, but the driver remains static, or when the environment variables in a Django management command don’t point where you think they do.

The error is a version mismatch between your installed Google Chrome browser and the chromedriver binary.

The Fix: Stop managing binaries manually. Use the webdriver-manager library to automatically fetch the compatible driver for your current browser version at runtime.

# pip install webdriver-manager selenium
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
options = webdriver.ChromeOptions()
options.add_argument("--headless") # Common for Django/Server environments
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=options)

When you run Selenium inside a Django context—whether it’s within tests.py, a custom management command, or an asynchronous Celery task—you are often running in an environment with different PATH constraints than your standard shell.

There are two primary reasons this fails:

  1. Version Drift: Chrome updates itself frequently. If your chromedriver was downloaded manually three months ago, it is now obsolete.
  2. Binary Location: Django applications often run under specific users (like www-data or a dedicated django user). If your driver is sitting in /usr/local/bin but the user doesn’t have execution permissions, or if you’re relying on a relative path that changes when the server starts, the session will fail to initialize.
Section titled “Solution 1: Automated Management (Recommended)”

Applies to: Python 3.8+, Selenium 4.x

The most robust way to handle this is to let the code determine the correct version. This is especially useful for teams where developers might be on different OSs (macOS vs Windows) but deploying to Linux.

# Illustrative example — verify in your environment
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from django.conf import settings
def get_selenium_driver():
options = webdriver.ChromeOptions()
# Critical for Django apps running on servers (no GUI)
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
# This line automatically downloads/updates the driver to match your Chrome version
service = ChromeService(executable_path=ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)
return driver

Why this works: ChromeDriverManager().install() checks your local Chrome version, compares it to the driver in its cache, and downloads a new one only if necessary. It returns the absolute path to the correct binary.

Solution 2: Explicit Binary Path (Best for Docker/CI)

Section titled “Solution 2: Explicit Binary Path (Best for Docker/CI)”

Applies to: Python 3.10+, Selenium 4.10+

If you are running Django inside a Docker container, you likely install a specific version of Chrome and Chromedriver via the Dockerfile. In this case, webdriver-manager might be overkill or might fail due to network restrictions.

# Illustrative example — verify in your environment
import os
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
def get_docker_driver():
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--headless")
# In Linux/Docker, these are often the standard paths
# Ensure these match your Dockerfile installation
chrome_service = Service(executable_path="/usr/bin/chromedriver")
chrome_options.binary_location = "/usr/bin/google-chrome"
driver = webdriver.Chrome(service=chrome_service, options=chrome_options)
return driver

Why this works: By explicitly setting binary_location and executable_path, you bypass the system’s PATH lookup entirely, preventing “session not created” errors caused by the wrong binary being picked up by the OS.


1. What about “DevToolsActivePort file doesn’t exist”?

Section titled “1. What about “DevToolsActivePort file doesn’t exist”?”

If you fix the “session not created” error but immediately hit this one, it’s usually because you are running as the root user (common in Docker). You must add the --no-sandbox and --disable-dev-shm-usage flags to your ChromeOptions. Django’s environment often lacks the shared memory size required by Chrome’s default settings.

2. Should I use Selenium or Playwright with Django?

Section titled “2. Should I use Selenium or Playwright with Django?”

While Selenium is the industry standard, many Django developers are moving to Playwright. Playwright handles driver management natively (no webdriver-manager needed) and has better support for the asynchronous nature of modern Django (ASGI). If you are starting a new project, it is worth comparing the two.

When using StaticLiveServerTestCase, put your driver setup in the setUpClass method and ensure you quit the driver in tearDownClass.

Feature Selenium 4.x Playwright
Driver Management External (needs manager) Internal (playwright install)
Async Support Limited Native
Django Integration Excellent (LiveServerTestCase) Good (pytest-django)
  • Use webdriver-manager to avoid manual binary updates.
  • Ensure --headless is enabled for server-side execution.
  • Check that the user running the Django process has execute permissions for the chromedriver binary.
  • If using Docker, pin the Chrome version in your apt-get or apk commands to prevent unexpected breakages during builds.