SessionNotCreatedException: Fix Driver Mismatch
Chrome updated past your chromedriver: let Selenium Manager resolve matching drivers, or pin both versions explicitly in CI images..
20+ years shipping production backend systems. Lessons pulled from things that broke in production.
- ✓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
- 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
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.
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.
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.
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.
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.
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.
Chrome 116 Auto-Update Reddened Every Suite Overnight
- 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.
| File | Command / Code | Purpose |
|---|---|---|
| io_thecodeforge | from selenium import webdriver | Selenium Manager |
| io_thecodeforge | from selenium import webdriver | Pinning Browser and Driver Together in CI |
| io_thecodeforge | from selenium import webdriver | Clearing Stale Drivers That Shadow the Fix |
| io_thecodeforge | from selenium import webdriver | Grid Nodes and Remote Sessions Drift Too |
Key takeaways
Common mistakes to avoid
5 patternsDowngrading Chrome to meet an old driver
Reinstalling browsers and drivers at random
Keeping executable_path overrides after upgrading Selenium
Resolving latest browser in CI for convenience
Debugging suite code for a startup failure
Interview Questions on This Topic
What causes SessionNotCreatedException most often?
Frequently Asked Questions
20+ years shipping production backend systems. Lessons pulled from things that broke in production.
That's Selenium. Mark it forged?
5 min read · try the examples if you haven't