Home › Testing › SessionNotCreatedException: Fix Driver Mismatch
Intermediate 5 min · September 23, 2026

SessionNotCreatedException: Fix Driver Mismatch

Chrome updated past your chromedriver: let Selenium Manager resolve matching drivers, or pin both versions explicitly in CI images..

N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Lessons pulled from things that broke in production.

Follow
✓ Production
production tested
September 27, 2026
last updated
2,085
articles · all by Naren
Before you start⏱ 10 min
  • ✓A Selenium script that launches Chrome at least once
  • ✓Basic comfort with pip packages and version numbers
  • ✓Access to the CI config or Dockerfile that runs your suite
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • SessionNotCreatedException at startup means chromedriver and Chrome versions disagree — usually Chrome auto-updated overnight
  • Read the message: it prints both versions, and the fix is making them match, not reinstalling everything
  • Modern Selenium ships Selenium Manager, which downloads the matching driver automatically — upgrade Selenium first
  • In CI, pin the browser and driver versions together in the image so green builds stay green
✦ Definition~90s read
What is Selenium SessionNotCreatedException?

SessionNotCreatedException is thrown when the browser session cannot start — the WebDriver handshake between your script, the driver binary, and the browser fails before navigation ever happens. The dominant cause is a chromedriver-to-Chrome version mismatch: each chromedriver release supports a narrow Chrome range, and Chrome's silent auto-updates walk the browser out of that range without warning.

★
Picture a lock and key cut as a pair.

The message helpfully prints both sides, such as driver 114 supporting Chrome 114 while the machine runs Chrome 116.

History explains the confusion. Before Selenium 4.6, engineers managed drivers by hand: downloading zips, setting executable paths, wiring webdriver-manager or vendored binaries. Countless tutorials still teach that ritual, so teams keep hand-managing what modern Selenium automates.

Since 4.6, Selenium Manager — bundled with the language bindings — detects the installed browser version and fetches the matching driver on first use, caching it per version. Most mismatch incidents on current Selenium mean the bindings themselves are outdated, not the driver.

The remaining causes are environmental: missing browser binaries on minimal CI images, sandbox flags absent in containers, stale cached drivers shadowing fresh ones, and Grid nodes whose browser and driver drifted apart. The professional posture is layered: current Selenium with Manager for local runs, explicitly pinned browser-plus-driver pairs in CI images for determinism, and version logging in setup so the next mismatch announces itself in the first log line.

Startup failures should be diagnosable in a minute, not a morning.

Plain-English First

Picture a lock and key cut as a pair. Overnight someone replaces the lock with a newer model, and your old key no longer turns — not because the key broke, but because the pair no longer matches. That is SessionNotCreatedException: Chrome updated itself and your chromedriver is suddenly the wrong key. The fix is getting a freshly cut key for the new lock, ideally from a locksmith — Selenium Manager — that cuts it automatically every morning.

No test runs at all. Every test fails in setup with SessionNotCreatedException, complaining the driver version only supports a Chrome version you no longer have. Yesterday everything was green. Nobody changed the suite. What changed was Chrome itself, silently auto-updating overnight past the chromedriver binary checked into your repo or cached on the runner.

This error is uniquely demoralizing because it strikes before any test logic executes — there is no flaky line to fix, no wait to tune. Beginners reinstall browsers and drivers at random, sometimes landing on a matching pair by luck, until the next auto-update breaks it again. The cycle repeats monthly because the root cause was never addressed: versions were paired by accident, not by management.

This guide makes driver management boring on purpose. You will learn to read the version mismatch message in seconds, let Selenium Manager resolve drivers automatically on modern Selenium, and pin browser-plus-driver pairs explicitly in CI images where determinism matters. By the end, Chrome updates become non-events instead of red mornings.

Reading the Mismatch Message in Ten Seconds

The exception message is unusually generous: it states the driver version, the browser version, and the supported range in plain text. A typical line says chromedriver 114 supports Chrome 114 while the session found Chrome 116 — diagnosis complete before you open a second tab. Yet teams routinely scroll past it hunting for suite bugs, because startup failures feel like infrastructure weather instead of readable errors.

Train the ten-second read: find the two version numbers, name which side moved, and update that side toward the other. Chrome moved via auto-update is the common case, so the driver follows the browser — upgrade bindings, clear vendored drivers, or bump the pinned driver. A moved driver after a careless image edit is rarer and fixed by re-pinning. Direction matters because downgrading browsers fights auto-update policies you will lose to eventually.

Log both versions in your session fixture so every CI log opens with the pairing evidence. One line printing selenium, browser, and driver versions turns the next red morning into a thirty-second comparison against yesterday's green log. Messages this clear deserve to be read — make them impossible to miss by echoing them into your own setup output.

📊 Production Insight
An on-call engineer bisected suite commits for two hours while the setup log quoted driver 114 against Chrome 116 from minute one. Version logging in the fixture would have ended it instantly. Rule: print the version pair at session start in every project.
🎯 Key Takeaway
The message prints both versions — read those before anything else.
Name which side moved, then update the driver toward the browser.
Log the version pair in setup so regressions compare in seconds.

Selenium Manager: Stop Hand-Managing Drivers

Selenium Manager ships inside modern Selenium bindings and ends the download-unzip-chmod ritual. On first driver use it detects the installed browser's version, fetches the matching driver from the official distribution, caches it per version, and hands back a working session. Chrome for Testing endpoints back the supply chain, so the resolved pairs are canonical rather than scraped. Most teams can delete their driver ClearlySetup code entirely.

Adoption is an upgrade plus a deletion. Bump the selenium package past 4.6 — current releases are well beyond it — then remove Service paths pointing at vendored binaries, webdriver-manager wiring kept only from habit, and README steps describing manual installs. The plain webdriver.Chrome() constructor with options is the whole integration now. Keep an allowlist for Manager's cache and download hosts if your network restricts egress, since first-run fetching needs to reach the distribution endpoints.

The snippet shows the minimal modern setup and the version-logging fixture worth adding. Notice what is missing: no paths, no zips, no version constants. That absence is the feature. Hand-management made sense when drivers were wild; today it is mostly a way to pin one half of a pair while the other half roams. Let the Manager own the pairing on developer machines and throwaway runners.

io_thecodeforge/manager_setup.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import selenium
from selenium import webdriver

def make_driver():
    options = webdriver.ChromeOptions()
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    # No Service path: Selenium Manager resolves the matching
    # chromedriver for the installed Chrome automatically.
    return webdriver.Chrome(options=options)

def log_versions(driver):
    print("selenium", selenium.__version__)
    print("browser", driver.capabilities["browserVersion"])
    print("chromedriver", driver.capabilities["chrome"]["chromedriverVersion"])
📊 Production Insight
A team kept a wiki page of driver download steps that every new hire followed to a different broken pairing. Upgrading bindings and deleting the page ended onboarding driver issues permanently. Rule: if your setup docs mention driver zips, they describe a problem you no longer need.
🎯 Key Takeaway
Selenium Manager detects the browser and fetches its matching driver.
Upgrade bindings past 4.6 and delete vendored driver paths.
Allowlist distribution hosts on restricted networks for first-run fetch.

Pinning Browser and Driver Together in CI

Automatics suit laptops; CI demands determinism. A pipeline that resolves latest at runtime can go red between runs with no commit, which destroys bisectability — the ability to blame a specific change for a failure. Pinned images fix both halves of the pair in one Dockerfile layer: a versioned browser install plus either Manager resolution against that exact browser or an equally versioned driver. Rebuilds are deliberate, logged, and reversible.

The pinning pattern installs Chrome from a versioned deb or the Chrome for Testing API at an explicit milestone, then smoke-tests session creation during the image build so a bad pair fails the build, not the test run. Dependabot or Renovate bumps the pins on schedule, and each bump runs the suite before merging — browser upgrades become ordinary tested changes. Keep the two versions adjacent in the Dockerfile with a comment naming the pairing, so no edit moves one without the other.

The snippet shows the shape: versioned install, build-time smoke test, runtime flags for containers. Note --no-sandbox and --disable-dev-shm-usage, without which Chrome crashes in unprivileged containers regardless of versions. Deterministic images plus Manager resolution inside them is belt and suspenders: the image fixes the browser, and resolution confirms the driver at runtime. Green builds stay green until you choose otherwise.

io_thecodeforge/ci_smoke.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from selenium import webdriver

CHROME_VERSION = "126.0.6478.126"  # paired with driver via Manager

def make_ci_driver():
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    options.add_argument("--window-size=1920,1080")
    driver = webdriver.Chrome(options=options)
    return driver

def smoke_test():
    driver = make_ci_driver()
    try:
        driver.get("about:blank")  # build fails here on bad pairs
        assert driver.session_id, "no session established"
        print("pair OK:", driver.capabilities["browserVersion"])
    finally:
        driver.quit()
📊 Production Insight
A pipeline resolving latest Chrome broke three times in a quarter with no suite changes, each incident eating a morning. Pinning the browser milestone and smoke-testing the pair at build time ended it. Rule: browsers upgrade on your schedule in CI, never on Google's.
🎯 Key Takeaway
Pin browser and driver versions together in one image layer.
Smoke-test session creation at build time, not at test time.
Automate pin bumps so upgrades stay tested and reversible.

Clearing Stale Drivers That Shadow the Fix

Upgrading bindings or pins sometimes changes nothing, and the culprit is a stale driver earlier on the resolution path. Vendored binaries committed to the repo, explicit Service paths in conftest, webdriver-manager caches from older setups, and Manager caches holding a corrupt download all shadow fresh resolution. Each one silently wins over the correct driver, so the mismatch persists through upgrades that should have fixed it.

Hunt methodically: list every chromedriver on PATH, print any Service executable_path in your fixtures, and inspect the Manager cache directory for stale entries. Remove committed binaries from the repo — drivers are resolved artifacts, not source code — and delete explicit paths so Manager decides. Where webdriver-manager remains in use, pin its driver version call explicitly rather than letting it float, or migrate that project to Manager and drop the dependency.

The snippet shows the audit commands plus the fixture shape that avoids shadowing. Run the audit once per project and once per runner image; stale drivers hide in both. After clearing, the version log from your fixture should show the expected pair on the next run. Resolution can only pick the right driver when no stale copy outranks it.

io_thecodeforge/driver_audit.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.webdriver.chrome.service import Service

def make_driver_no_shadow():
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    # No executable_path: any hardcoded path here would shadow
    # Selenium Manager and reintroduce the mismatch by hand.
    return webdriver.Chrome(options=options)

# Shell audit for stale drivers (run on the runner):
#   which -a chromedriver
#   ls ~/.cache/selenium
#   grep -rn "executable_path" tests/ conftest.py
⚠ Committed Drivers Rot Silently
A chromedriver binary in your repo is a version pair frozen at commit time while browsers keep moving. Delete vendored drivers and let resolution happen at runtime — binaries are build artifacts, not source code.
📊 Production Insight
An upgrade to Selenium 4.20 changed nothing because conftest still passed an executable_path to a 114 binary. The hardcoded path outranked Manager for months. Rule: grep for executable_path in every repo yearly; each hit is a future red morning.
🎯 Key Takeaway
Audit PATH, caches, and fixtures for drivers that outrank fresh resolution.
Delete committed binaries and hardcoded Service paths.
Verify the version log shows the expected pair after clearing.

Grid Nodes and Remote Sessions Drift Too

Remote WebDriver moves the handshake to the node, and nodes drift independently. Your laptop's perfect pairing means nothing when the Grid node runs last quarter's Chrome against this quarter's driver — the session fails with the same mismatch wearing a remote traceback. Node images updated on different schedules are the usual cause: infrastructure patches browsers while the test image pins drivers, or vice versa.

Debug at the node, not the client. The Grid console exposes node versions, and a direct version check over SSH settles it in seconds. Pair node browser and driver in a single image build with the same pinning discipline as CI runners, and roll nodes and hubs together so no node serves sessions its pair cannot honor. Log the node's reported versions in your remote fixture to keep the evidence client-side.

The snippet shows a remote fixture with node version logging. When mismatches appear, compare the logged node pair against the known-good pins instead of debugging test code. Grid multiplies capacity and multiplies version surfaces — each node is a pairing you own. Treat node images as release artifacts with versions, changelogs, and rollback, and remote mismatches become as rare as local ones.

io_thecodeforge/grid_pair.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver

GRID_URL = "http://grid-hub:4444/wd/hub"

def make_remote_driver():
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    driver = webdriver.Remote(command_executor=GRID_URL, options=options)
    caps = driver.capabilities
    print("node browser", caps.get("browserVersion"))
    print("node driver", caps.get("chrome", {}).get("chromedriverVersion"))
    return driver
📊 Production Insight
A Grid fleet patched node browsers on Fridays while test images pinned drivers from Monday, breaking every weekend run for a month. Locking node browser and driver in one image ended the Friday curse. Rule: nodes and hubs roll together as one versioned release.
🎯 Key Takeaway
Remote mismatches live on the node — check versions there first.
Pin node browser and driver in a single image build.
Log node-reported versions in the remote fixture for client-side evidence.

Making the Next Mismatch a One-Minute Fix

Prevention is instrumentation plus policy. Instrumentation means the version log in every fixture, the build-time smoke test in every image, and a dashboard alert when runner browser versions change without a matching suite run. Policy means pinned CI pairs, Manager resolution elsewhere, no committed drivers, and browser upgrades as scheduled tested changes. Together they compress each future incident to version comparison plus a pin bump.

Write the runbook entry while this incident is fresh: symptom signature, the two version commands, the upgrade-or-pin decision tree, and the rollback step. Link it from the fixture's error message if your framework allows custom setup messages — the engineer who meets this at 8 AM should land on instructions, not a blank search box. Review the pins quarterly even when green, because silent drift is only silent until morning.

The deeper lesson is that startup dependencies deserve the same rigor as application dependencies. Lockfiles pin libraries; images must pin browsers with equal seriousness. A suite that manages its runtime this way treats Chrome releases as calendar events with owners and dates. The next mismatch still arrives eventually — but it arrives as a ticket with versions attached, fixed in minutes by whoever is on call.

📊 Production Insight
A team added version logging, pin bumps via Renovate, and a runbook link after their noon outage — the next Chrome release produced a ten-minute ticket instead of a half-day incident. Rule: convert every incident's confusion into logging that prevents its repeat.
🎯 Key Takeaway
Instrument versions, smoke-test pairs, and alert on runner drift.
Keep a runbook linked from setup so on-call lands on instructions.
Treat browser pins with the rigor of dependency lockfiles.
● Production incidentPOST-MORTEMseverity: high

Chrome 116 Auto-Update Reddened Every Suite Overnight

Symptom
All suites on self-hosted runners failed in fixture setup with SessionNotCreatedException: driver 114 supports Chrome 114, machines ran Chrome 116. No test executed a single step. Cloud CI on pinned images stayed green, which isolated the blast to the self-hosted fleet that allowed browser auto-updates.
Assumption
The first responder assumed a bad deploy of the test framework because every suite broke simultaneously. Two hours went into bisecting suite commits that changed nothing. The actual change was underneath the suite entirely: the fleet's package manager had rolled Chrome 114 to 116 overnight per its unattended-upgrades policy.
Root cause
Chromedriver was vendored at 114 in the runner image while Chrome installed from a repository that auto-updated. Nothing paired the two versions, so routine browser maintenance broke the handshake. The mismatch message stated both versions from the first failure, but the team debugged the suite instead of reading setup output.
Fix
Runners were switched to Selenium Manager resolution by upgrading the Selenium bindings past 4.6 and deleting the vendored driver, so each run fetches the driver matching the installed Chrome. Unattended browser upgrades were kept, since mismatches can no longer occur. Suites were green by noon and stayed green through the next two Chrome releases.
Key lesson
  • Read setup failures first: the mismatch message prints both versions and the fix is pairing them, not bisecting suite code.
  • Never vendor one half of a version pair while the other half auto-updates — manage both or automate the pairing.
  • Self-hosted runners need the same version discipline as CI images, or they become the fleet's weakest morning.
Production debug guideFive steps that pair the driver to the browser in minutes.5 entries
Symptom · 01
The message cites driver versus browser versions
→
Fix
Note both numbers — the fix is making them agree. Check your Selenium version with pip show selenium: below 4.6, upgrade past it so Selenium Manager resolves drivers automatically. Above 4.6 with a vendored driver path, delete the override and let Manager fetch the match.
Symptom · 02
Failures began overnight with no suite changes
→
Fix
Suspect a browser auto-update: compare chrome --version today against yesterday's CI logs. Confirm the driver side with chromedriver --version or the Manager cache listing. The side that moved dictates the fix — update the driver to the browser, never downgrade the browser to the driver.
Symptom · 03
It fails in containers but passes on laptops
→
Fix
Minimal images often lack the browser entirely or ship mismatched pairs. Print google-chrome --version and the driver version in the Dockerfile build log. Install both from versioned sources in one layer, add --no-sandbox and --disable-dev-shm-usage flags, and verify with a one-line session smoke test during the build.
Symptom · 04
A stale cached driver shadows the correct one
→
Fix
Find every chromedriver on PATH and in Manager cache: which -a chromedriver plus the cache directory listing. Explicit Service paths and webdriver-manager caches override Manager silently. Remove vendored copies, clear the stale cache entry, and rerun so resolution happens fresh.
Symptom · 05
Grid or remote sessions fail while local passes
→
Fix
The mismatch lives on the node, not your machine. Query the node's browser and driver versions directly — Grid console or SSH — and pair them there. Pin node images with both versions locked, since a node updating its browser independently breaks every session it accepts.
SessionNotCreatedException Causes Compared
Root CauseHow to ConfirmFixPrevention
Chrome auto-updated past vendored chromedriverMessage quotes driver 114 against Chrome 116Upgrade Selenium for Manager resolution; delete vendored driverNo committed drivers; Manager owns local pairing
Outdated Selenium without Selenium Managerpip show selenium below 4.6 with manual driver setupUpgrade bindings past 4.6 and remove manual wiringPin a floor version for selenium in requirements
CI image with unpaired browser and driverFails in containers, passes on laptopsInstall both versioned in one layer; smoke-test the pairAutomated pin bumps with suite runs before merge
Grid node browser and driver drifted apartLocal passes while remote sessions fail identicallyPair versions in the node image; roll nodes with hubsNode images as versioned releases with rollback
⚙ Quick Reference
4 commands from this guide
FileCommand / CodePurpose
io_thecodeforgemanager_setup.pyfrom selenium import webdriverSelenium Manager
io_thecodeforgeci_smoke.pyfrom selenium import webdriverPinning Browser and Driver Together in CI
io_thecodeforgedriver_audit.pyfrom selenium import webdriverClearing Stale Drivers That Shadow the Fix
io_thecodeforgegrid_pair.pyfrom selenium import webdriverGrid Nodes and Remote Sessions Drift Too

Key takeaways

1
The message names both versions
pair the driver to the browser, never the reverse.
2
Modern Selenium resolves drivers via Manager; upgrade bindings and delete manual wiring.
3
Pin browser-plus-driver pairs in CI images with build-time smoke tests.
4
Audit PATH, caches, and fixtures for stale drivers shadowing resolution.
5
Pair Grid node versions in single images and roll fleets together.
6
Log the version pair at session start so the next mismatch takes a minute.

Common mistakes to avoid

5 patterns
×

Downgrading Chrome to meet an old driver

Symptom
Works until the next auto-update re-breaks it, fighting platform policy with manual installs on every machine and runner.
Fix
Move the driver toward the browser instead: upgrade bindings for Manager resolution or bump the pinned driver. Never anchor to a browser version you cannot hold.
×

Reinstalling browsers and drivers at random

Symptom
Occasional lucky pairs that rot within weeks, with nobody able to say which versions are supposed to match.
Fix
Read the message's two versions, then apply one deliberate pairing change. Log the pair in setup so the intended match is always visible.
×

Keeping executable_path overrides after upgrading Selenium

Symptom
Modern bindings still fail identically because a hardcoded Service path outranks Manager and points at the ancient binary.
Fix
Delete executable_path overrides and vendored binaries. Let Manager resolve, and verify via the setup version log.
×

Resolving latest browser in CI for convenience

Symptom
Red builds with no commits, unbisectable failures, and upgrade incidents arriving on release days.
Fix
Pin browser and driver in the image and bump via automation with suite runs. Upgrades become scheduled, tested changes.
×

Debugging suite code for a startup failure

Symptom
Hours bisecting test commits while setup logs quote the version mismatch from the first line of output.
Fix
Read setup output first for any session failure. No test executed means the suite is innocent until the handshake passes.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What causes SessionNotCreatedException most often?
Q02SENIOR
What is Selenium Manager and when did manual driver setup stop being nee...
Q03SENIOR
Why pin browser versions in CI instead of using latest?
Q04SENIOR
A hardcoded Service path survives your Selenium upgrade. What breaks?
Q05SENIOR
Local sessions pass but Grid sessions fail. Where do you look?
Q01 of 05JUNIOR

What causes SessionNotCreatedException most often?

ANSWER
A chromedriver-to-Chrome version mismatch, usually from Chrome auto-updating past a pinned or vendored driver. The message prints both versions. The fix pairs them: upgrade Selenium so Manager resolves the match, or pin both versions together in CI images.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Should I use webdriver-manager or Selenium Manager?
02
Where does Selenium Manager cache drivers?
03
Can I just disable Chrome auto-updates instead?
04
Why do containers need --no-sandbox and --disable-dev-shm-usage?
05
How do I know which chromedriver supports my Chrome?
06
The error mentions DevToolsActivePort. Is that a mismatch?
N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Lessons pulled from things that broke in production.

Follow
✓ Verified
production tested
September 27, 2026
last updated
2,085
articles · all by Naren
🔥

That's Selenium. Mark it forged?

5 min read · try the examples if you haven't

←
Previous
Selenium NoSuchElementException — Waits, Not sleep()
4 / 5 · Selenium
Next
Selenium TimeoutException in Headless but Not Headed
→