Resource library

QA How-To

How to Fix Selenium "DevToolsActivePort file doesn't exist"

Fix Selenium DevToolsActivePort file doesn't exist with targeted checks for Chrome startup, profiles, Docker shared memory, CI, Grid, and driver compatibility.

19 min read | 3,587 words

TL;DR

Run a minimal headless Chrome session with a fresh profile and inspect ChromeDriver's verbose log. Fix the specific startup blocker, commonly a locked profile, insufficient Docker shared memory, root execution, a wrong browser binary or driver pair, or CI resource pressure, then rerun the same test on the failing worker.

Key Takeaways

  • Treat the missing DevToolsActivePort file as evidence that Chrome did not finish startup.
  • Use a minimal headless Selenium session and verbose ChromeDriver log to isolate the failure.
  • Give each browser session a unique writable profile if you override Chrome's default.
  • Size Docker shared memory for Chrome and run Linux browser processes as a regular user.
  • Check the actual Chrome binary and driver pair used by the failing worker or Grid node.
  • Verify the repair under the original account, image, and concurrency conditions.

If you need to fix Selenium DevToolsActivePort file doesn't exist, start by checking why Chrome exits before ChromeDriver creates a WebDriver session. The error usually appears at webdriver.Chrome(...) or when a Selenium Grid node launches Chrome, before your test navigates to a page.

selenium.common.exceptions.SessionNotCreatedException: Message: session not created: Chrome failed to start: exited normally.
(session not created: DevToolsActivePort file doesn't exist)
(The process started from chrome location /opt/google/chrome/chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)

The Chrome path and the first line vary by operating system and release. The missing file is a symptom of incomplete startup, not a file you should create by hand. Use the process, profile, and driver evidence below to find the actual failure.

TL;DR

Run a minimal headless Chrome session with a clean profile and current Selenium. If it passes, reintroduce your original flags and profile one at a time. If it fails, capture ChromeDriver's verbose log and launch the exact Chrome binary outside WebDriver. In Docker, give Chrome enough shared memory; on Linux, run it as a regular user. ChromeDriver's startup guide specifically recommends testing the same binary and flags from the same execution environment.

python -m pip install -U selenium
python smoke_chrome.py

The script appears in section 1. A passing run prints PASS: Chrome session started with the browser version. If your CI worker cannot reach the package index, install the Selenium release approved by your project instead of forcing an upgrade during every job. The code uses Selenium Manager through the normal constructor, so it does not require a manually downloaded ChromeDriver in the common case.

What the Error Actually Means

ChromeDriver starts a Chrome process and waits for a usable browser debugging connection. With the usual startup path, Chrome writes a DevToolsActivePort file in its user data directory once the debugging endpoint is ready. If Chrome exits, cannot write its profile, or never reaches that point, ChromeDriver reports that the file does not exist. The report describes what ChromeDriver could not observe; it does not identify the root cause.

A browser failure may be hidden behind a long Selenium stack trace. Read the lines just above and below session not created, then look in the ChromeDriver log for the Chrome binary path, launch arguments, and Chrome stderr. Check whether the failure happens before navigation. If no WebDriver session exists, changing waits or element locators cannot help. A driver mismatch can also prevent session creation, but it has its own explicit messages, so read the whole exception rather than treating every startup failure as a version problem.

ChromeDriver and Chrome run in different processes. The browser can be installed correctly for your interactive desktop yet unavailable to a service account, container, or Grid node. The ChromeDriver logging guide documents verbose driver logs and the CHROME_LOG_FILE option for Chrome stderr. Collect both when the first minimal run fails. Review the related Chrome not reachable troubleshooting guide if a session starts and crashes later; that is a different point in the lifecycle.

Root-Cause Decision Table

Symptom Root cause to test first Fix and proof
Local desktop works; CI has no display Chrome launched headed in an unattended worker Set --headless; rerun the same smoke test in CI
Failure begins after adding --user-data-dir Profile locked, shared, missing, or unwritable Remove the override or use a fresh writable directory per session
Docker fails under load; /dev/shm is small Chrome cannot use enough shared memory Increase container --shm-size; compare the same test before and after
Linux container runs Chrome as root Sandbox startup restriction Run as a regular user; verify id -u and session creation
Error started after image or browser update Wrong Chrome binary or incompatible explicit driver Inspect versions and paths; let Selenium Manager resolve the driver or match the pair
Chrome binary fails without Selenium Missing OS libraries, damaged install, bad flags, or permissions Fix the browser installation and rerun Chrome directly
Only parallel CI shards fail Memory, process, or profile contention Lower concurrency, isolate profiles, and measure worker resources
Local passes but Grid fails Browser runs on a remote node with different resources or options Test the node, not the client machine; inspect node logs

Start with one browser and one test. The table is a triage order, not a list of flags to apply together. Each numbered section gives a specific observation and a command that can show whether its fix worked.

1. Fix Selenium DevToolsActivePort File Doesn't Exist in Headless CI

Create smoke_chrome.py with this complete Selenium Python example. It keeps the launch options small, uses a headless browser by default, and writes a verbose ChromeDriver log for local sessions. The REMOTE_URL switch lets the same probe test a Grid node later. Set HEADLESS=0 only when a real display is available. Options.add_argument, ChromeService, and webdriver.Remote are public Selenium APIs; the Selenium Python documentation shows the current driver construction pattern.

import os
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service as ChromeService

options = Options()
if os.environ.get("HEADLESS", "1") == "1":
    options.add_argument("--headless")
options.add_argument("--window-size=1280,800")
if os.environ.get("CHROME_BINARY"):
    options.binary_location = os.environ["CHROME_BINARY"]
if os.environ.get("CHROME_PROFILE"):
    options.add_argument("--user-data-dir=" + os.environ["CHROME_PROFILE"])
if os.environ.get("CHROME_DEV_SHM_FALLBACK") == "1":
    options.add_argument("--disable-dev-shm-usage")

remote_url = os.environ.get("REMOTE_URL")
if remote_url:
    driver = webdriver.Remote(command_executor=remote_url, options=options)
else:
    log_path = Path("chromedriver.log").resolve()
    service = ChromeService(service_args=["--verbose"], log_output=str(log_path))
    driver = webdriver.Chrome(service=service, options=options)

try:
    driver.get("https://www.selenium.dev/")
    assert "Selenium" in driver.title, driver.title
    print("PASS: Chrome session started", driver.capabilities["browserVersion"])
finally:
    driver.quit()

Verify from a Python environment that contains Selenium and has network access to the Selenium site:

python smoke_chrome.py

If startup still fails, inspect chromedriver.log in the working directory. The page assertion can fail because of a proxy or outbound network policy after the session starts; in that case the DevToolsActivePort startup issue is already resolved. You can replace the URL with an approved internal page for an offline worker. If a headed run fails only in CI, keep HEADLESS=1; Chrome's headless documentation confirms --headless is the supported unattended mode. Avoid older recipes that require a separate obsolete headless implementation.

2. Fix Selenium DevToolsActivePort File Doesn't Exist From a Locked Profile

Search your framework for --user-data-dir, --profile-directory, or a hard-coded Chrome profile path. Two Chrome processes using the same user data directory can collide. A profile copied from a developer machine may also contain state that is incompatible with the worker's account or browser. ChromeDriver normally creates a temporary profile, so first remove all explicit profile options and run python smoke_chrome.py again. If that succeeds, the profile customization is the discriminating change.

When you truly need a custom user data directory, allocate one per browser session and ensure the process can write to it. The script in section 1 accepts CHROME_PROFILE, so this Linux or macOS shell command runs one isolated session and removes only its own temporary directory afterward:

profile_dir="$(mktemp -d)"
trap 'rm -rf "$profile_dir"' EXIT
CHROME_PROFILE="$profile_dir" python smoke_chrome.py

Verification is the printed PASS line. To prove a permissions issue, test directory writability as the same user that starts Chrome:

id
profile_dir="$(mktemp -d)"
test -w "$profile_dir" && echo "writable profile directory"

This check alone does not prove Chrome can start, so follow it with the session probe. Do not point a parallel test suite at your normal Chrome profile. If login state is needed, create it through your test setup or use a separate profile per worker. Do not delete an existing user's profile as a cleanup shortcut. A reproducible profile allocation policy matters more than a one-time deletion of Chrome lock files.

3. Repair Docker Shared Memory Before Adding Browser Flags

Docker's default shared memory allocation can be too small for Chrome, especially with multiple tabs or sessions. The official Selenium Docker repository recommends --shm-size="2g" for browser containers and says to tune it for the workload. Use the repository's currently approved full image tag; the placeholder below must be replaced with a tag that exists and matches your deployment.

docker run --rm -d --name chrome-probe -p 4444:4444 \
  --shm-size=2g selenium/standalone-chrome:<your-approved-full-tag>
for attempt in $(seq 1 30); do
  curl -fsS http://localhost:4444/status && break
  sleep 1
done
REMOTE_URL=http://localhost:4444 python smoke_chrome.py

The status endpoint confirms Grid is listening; the PASS line proves a Chrome session starts inside that container. The Python client does not need local Chrome for this remote probe. If you use Docker Compose, put shm_size: 2gb on the browser service and verify with docker compose config before rerunning the test. The meaningful comparison is the same image, node, and test with enough shared memory.

--disable-dev-shm-usage is a fallback that redirects Chrome away from /dev/shm on Linux. It can help when the container's shared memory setting cannot be changed, but it is not a universal repair for bad profiles, missing libraries, or version mismatches. Test that branch with CHROME_DEV_SHM_FALLBACK=1 python smoke_chrome.py only after confirming the small shared-memory condition. For a remote Grid browser, set the Chrome option in the client that creates the remote session, then compare node logs. Avoid passing Docker flags to the Python process; Docker memory is configured where the browser container starts.

4. Run Chrome as a Regular User on Linux

Chrome's sandbox can fail when Chrome is started as root in a Linux container or service. The ChromeDriver startup guidance recommends running as a normal user and explicitly discourages --no-sandbox as an unsupported workaround. Many copied CI snippets add that flag reflexively, masking the service account problem and weakening isolation. Check the effective user where the browser process runs, not only in your terminal.

id -u
id -un
python smoke_chrome.py

A UID of 0 identifies root on Linux. Reconfigure the container or CI job to run the test as a non-root account with a writable home, cache, and temporary directory. For a custom Dockerfile, create and select that account before the test command; use your base image's existing non-root browser user when it provides one. Keep the Chrome and Selenium cache directories writable to that account. Verify inside the browser container with docker exec chrome-probe id -u, then run the remote smoke test again.

If changing the user is blocked by infrastructure policy, document the constraint and involve the image owner. Do not silently make --no-sandbox a global test-framework default. A passing session under root with that flag would only show that a sandbox check was bypassed; it would not demonstrate a sound container setup. If id -u is nonzero, move on to the browser log instead of changing sandbox options.

5. Check the Actual Chrome Binary and Driver Pair

Version errors are easiest to diagnose when you know which binaries started. A local chromedriver --version can be irrelevant if Selenium Manager selected a different driver, and google-chrome --version can be irrelevant if options.binary_location points elsewhere. Read chromedriver.log for the Chrome path and command line. The ChromeDriver version selection guide explains how to pair Chrome for Testing with its driver; the Selenium error guide lists incompatible versions as one cause of SessionNotCreatedException.

On Linux, inspect the command candidates and your Python binding without hard-coding a release:

python -m pip show selenium
command -v google-chrome || command -v chromium || true
command -v chromedriver || true
google-chrome --version || chromium --version || true
chromedriver --version || true

Then run the section 1 probe without CHROME_BINARY or a manually configured driver path. Current Selenium can use Selenium Manager to locate or obtain compatible components. If the clean probe passes but your framework fails, remove its stale executable override or update the explicit pair according to your installed browser. If a company image fixes browser versions, keep its Chrome and driver in the same image and verify the pair as part of image updates. The success check is python smoke_chrome.py using the same binary path as the original job, not a version number printed in isolation.

On macOS or Windows, use the browser path from the ChromeDriver log and your platform's version command. A Chrome update can change which binary a service account sees. When testing a non-default Chrome executable, set CHROME_BINARY to its absolute path for the probe, then verify the log shows that path. Do not guess a ChromeDriver download URL or pin a random historical release to suppress a startup error.

6. Launch Chrome Without Selenium to Find OS-Level Failures

When the minimal Selenium probe still exits, run the exact Chrome binary directly as the same user, with the same headless setting. This separates browser startup from ChromeDriver and Python. ChromeDriver's own troubleshooting page recommends this isolation step. On Linux, the following probes use the Chrome executable installed at google-chrome; substitute the exact path shown in your ChromeDriver log if it differs.

command -v google-chrome
CHROME_LOG_FILE="$(pwd)/chrome-stderr.log" \
  google-chrome --headless --dump-dom about:blank

Expected output includes a minimal HTML document. Inspect chrome-stderr.log when the process exits before rendering. Missing shared libraries, a read-only home directory, an invalid flag, and a damaged browser installation produce different diagnostics. If google-chrome is absent, check chromium or the path chosen by Selenium Manager rather than assuming one package name. Use ldd on the browser executable on Linux when the stderr names a missing library; install the required system package in the image, then repeat the direct command.

On macOS, launch the Chrome executable inside the application bundle; on Windows, invoke the full chrome.exe path from PowerShell. Keep the same account and environment variables as the failing job. If direct Chrome works but WebDriver fails, compare the ChromeDriver launch arguments in chromedriver.log with the direct invocation. Remove custom flags one at a time and rerun python smoke_chrome.py. Do not paste a large list of community flags into every session: the extra switches can conceal which dependency is broken.

7. Reduce CI Resource and Parallel-Session Contention

If one smoke test passes but several parallel jobs fail intermittently, record memory, shared memory, process count, and concurrent browser count at the time of failure. A browser can disappear before creating DevToolsActivePort because the worker or container kills it under pressure. The same symptom can come from profile reuse: two shards may both launch with the same --user-data-dir. Those cases require different repairs, so separate them with an isolated one-session run.

Run a baseline and a small controlled concurrency experiment on the same worker:

python smoke_chrome.py
free -h
df -h /dev/shm

For a second probe, launch separate processes without a shared CHROME_PROFILE, then inspect both exit statuses:

python smoke_chrome.py & first=$!
python smoke_chrome.py & second=$!
wait "$first"; first_status=$?
wait "$second"; second_status=$?
printf 'first=%s second=%s\n' "$first_status" "$second_status"

Both statuses should be zero. If a single session passes but two fail under the same worker limits, lower concurrency or increase worker resources based on observed pressure. If failures stop only after removing the shared profile argument, keep concurrency and fix profile allocation instead. Log resource observations beside the ChromeDriver and container logs so future regressions can be traced to an image or capacity change. The CI flakiness guide covers how to keep such experiments repeatable instead of turning an intermittent startup failure into a blind retry.

8. Diagnose the Browser on the Selenium Grid Node

A remote session moves Chrome startup to the node. Changing a Chrome installation on the Python client will not repair a containerized node. First confirm Grid health, then run the same probe remotely with REMOTE_URL. Inspect the node or standalone container's logs for the Chrome process failure. The Docker for Selenium Grid guide helps map client, router, and browser node responsibilities.

curl -fsS http://localhost:4444/status
REMOTE_URL=http://localhost:4444 python smoke_chrome.py
docker logs chrome-probe

A healthy Grid status does not prove that Chrome can start, because the status endpoint checks the service rather than completing your session. A remote PASS does. If the client reports a session creation error, examine the node's browser version, UID, profile path, and /dev/shm allocation. Apply the relevant fix to that node image or service. Do not copy a local chromedriver executable into the client container in response to a remote browser crash.

The REMOTE_URL path in the shared script uses webdriver.Remote(command_executor=..., options=options), so it sends Chrome options to Grid. Do not add a local ChromeDriver Service to that branch. If you have multiple nodes, test the failing node's image or isolate its container; a passing request through the router may land on a different healthy node. Compare capabilities from the passing session with the failing node's configured browser image before closing the incident.

How to Verify the Fix

A fix is demonstrated by the session starting repeatedly under the original execution conditions. Run the one-session probe on the laptop or worker that failed. Confirm the PASS line and record driver.capabilities["browserVersion"] from the script. Then run the original test without restoring unrelated flags. If the original test still fails during page interaction, it is a separate failure after startup and needs its own diagnosis.

Use this short verification sequence in CI after changing an image, profile policy, or runner configuration:

python -m pip show selenium
python smoke_chrome.py
python smoke_chrome.py

The second run catches leftover profile locks and cleanup mistakes. For Docker or Grid, prefix both runs with the same REMOTE_URL used by the suite and collect node logs if either run fails. For parallel suites, repeat the controlled two-process check from section 7. Compare the logs before and after the single chosen fix: the Chrome binary path, effective user, launch options, and container memory setting should explain why the result changed.

Do not claim success because the exception disappeared after a retry. A retry may choose a different node or hide a memory race. The verification must exercise the same browser process location, account, image, and concurrency class that originally failed. If you need a broader Python Selenium framework around this probe, use the Selenium Python framework tutorial after the small session startup check is stable.

Prevent It From Coming Back

Keep browser startup as a small CI smoke gate before expensive end-to-end tests. Log the browser and driver versions selected by the job, the browser binary path, and the worker image identifier. Pin an approved full Selenium Docker image tag after testing it, and update browser and driver together. On normal local Selenium runs, let Selenium Manager handle driver discovery unless your environment has a controlled explicit pair.

Make profile creation per session and cleanup unconditional. Run browser containers as a regular user, size shared memory for observed workload, and bound parallel sessions to the worker's capacity. Keep custom Chrome flags in one reviewed configuration point. A new flag should have a named reason and a verification case; accumulated folklore makes the next startup incident harder to diagnose.

Capture verbose ChromeDriver logs only when useful, with a retention policy that protects test data. The Chrome stderr file can contain URLs and other context. For CI evidence and operational context, see CI/CD troubleshooting interview questions for QA. The durable outcome is a reproducible browser environment, not an ever-growing set of exception-specific workarounds.

Interview Questions and Answers

Q: What does DevToolsActivePort file doesn't exist prove?

It proves ChromeDriver did not observe Chrome's expected debugging endpoint during session startup. It does not prove that the file itself is corrupt or identify why Chrome exited. I would inspect ChromeDriver verbose logs and run the same Chrome binary directly.

Q: Why can this pass locally and fail in CI?

The browser runs under a different account, display setup, image, profile location, and resource limit in CI. I would run a minimal headless session on that exact worker, then compare its Chrome binary and arguments with the desktop run. That narrows the difference before changing flags.

Q: Is --no-sandbox a good default fix?

No. ChromeDriver's official startup guide discourages it as an unsupported workaround for root execution. I would first run the browser as a regular user with writable directories, then prove the session starts under that account.

Q: When would --disable-dev-shm-usage help?

It is relevant when Linux container shared memory is constrained and Chrome fails during startup. I would prefer sizing /dev/shm for the browser workload, compare the same image with a larger --shm-size, and use the flag only as a measured fallback.

Q: How do you distinguish a profile collision from a driver mismatch?

I remove custom profile arguments and retry with a fresh session. If that succeeds, I test a unique writable directory per process. For a mismatch, I inspect the full session error plus the actual Chrome and ChromeDriver paths and versions rather than the profile filesystem.

Q: What changes when the browser runs on Selenium Grid?

Chrome starts on a node, not the client machine. I send Chrome options with webdriver.Remote, inspect the node logs and resource limits, and verify a session on the same node image. Updating the client's local Chrome installation is irrelevant to that browser process.

Common Mistakes

  • Creating an empty DevToolsActivePort file. ChromeDriver needs a live debugging endpoint, not merely a file with that name. A manually created file hides the signal and cannot make a dead Chrome process respond.
  • Adding every suggested Chrome flag at once. This removes the ability to attribute a passing run to a specific cause. Change one condition, rerun the same probe, and keep only the justified option.
  • Using a developer's everyday profile in automation. It can be locked, contain incompatible state, or leak personal data into CI artifacts. Use the ChromeDriver-managed temporary profile unless a test explicitly needs isolated persisted state.
  • Checking only the client container in Grid. The browser may be crashing in a remote node with a different binary and memory limit. Read the node log and verify a remote session.
  • Treating one retry as a repair. A retry can avoid a transient node or resource spike. Confirm repeated startup under the original concurrency and preserve logs that explain the change.
  • Hard-coding a random driver release. Check the actual browser binary and pair it with a compatible driver, or let Selenium Manager select components in supported environments. The ChromeDriver mismatch guide covers the separate version-specific error path.

Conclusion

To fix Selenium DevToolsActivePort file doesn't exist, prove first that Chrome can start as the same user, in the same container or node, with the same binary and essential flags as the failing test. A clean headless smoke session gives you a baseline. Profile isolation, shared memory, sandbox user, binary compatibility, and worker capacity each have a distinct verification step.

Keep the smallest change that makes both the probe and original suite pass repeatedly. Preserve the ChromeDriver log for the next browser or image update, and use the decision table to investigate the first new symptom instead of recreating a missing file or collecting more unexplained flags.

Interview Questions and Answers

What does the missing DevToolsActivePort message actually mean?

ChromeDriver did not observe the expected browser debugging endpoint during session creation. That can happen because Chrome exited or could not initialize its profile. I would treat the message as a startup symptom and inspect the Chrome process and verbose driver log for the cause.

How would you debug a CI-only DevToolsActivePort failure?

I would run a one-session headless probe on the same worker under the same account. Then I would compare the Chrome binary, launch arguments, writable directories, and resource limits against a passing run. I would make one change at a time and rerun the probe and original test.

Why is --no-sandbox a poor default response?

It bypasses a browser isolation control and can mask Chrome running as root. ChromeDriver's official guidance discourages that configuration. I would configure a non-root browser user and verify the session starts with the sandbox available.

How can Docker shared memory cause this symptom?

Chrome uses shared memory during startup and rendering. A browser container with too little /dev/shm can exit before ChromeDriver finishes session creation. I would increase the browser container's shm size, compare the same test before and after, and tune the allocation to measured workload.

How do you identify a Chrome profile collision?

I would remove the explicit --user-data-dir and retry with ChromeDriver's temporary profile. If the clean run works, I would allocate a unique writable profile per process and check for parallel workers using the same path. I would not delete a user's normal profile to make a test pass.

How do you verify the right ChromeDriver is used?

I would read the ChromeDriver log for the actual Chrome executable and inspect the configured driver path or Selenium Manager selection. Printed versions from arbitrary PATH binaries can mislead when the test uses another executable. I would then verify a real session with the same browser and driver pair.

What is different about this error on Grid?

The Chrome process lives on the remote node. I would inspect its browser image, UID, profile, memory, and logs, then send a minimal Remote WebDriver request with Chrome options. Changing the client machine's Chrome binary would not repair a node process.

Frequently Asked Questions

What is the DevToolsActivePort file in Selenium?

Chrome can write this file in its user data directory while establishing a debugging endpoint for ChromeDriver. If the browser exits before that endpoint is ready, ChromeDriver reports the file as missing. Creating the file yourself will not establish a working browser connection.

Does DevToolsActivePort file doesn't exist always mean a ChromeDriver version mismatch?

No. A mismatched explicit driver can cause session creation failures, but a locked profile, root sandbox issue, missing library, or memory pressure can produce the DevToolsActivePort symptom. Read the full error and the ChromeDriver log before replacing a driver.

How do I fix this error in Docker?

Run the smoke test inside or against the same browser container, inspect its logs, and increase shared memory with Docker's --shm-size when it is constrained. Check that the browser runs as a regular user and can write its profile. Use a full image tag approved for your Chrome and Grid release.

Should I add --no-sandbox to ChromeOptions?

Do not make it a default repair. ChromeDriver's startup documentation discourages this workaround for root execution. Run Chrome as a non-root user and verify the account has writable home and temporary directories.

Can headless mode solve the error in CI?

Yes, if Chrome was trying to open a headed window on a worker without a display. Add the supported --headless option and rerun a minimal session on that worker. If the browser still exits, use its log to investigate the next cause.

Why does a fresh Chrome profile help?

A shared profile can be locked by another Chrome process, while a copied or read-only profile can fail during startup. ChromeDriver normally manages a temporary profile. If you need an override, allocate a unique writable directory for every session.

What should I inspect when this happens on Selenium Grid?

Inspect the browser node's ChromeDriver and container logs, user, binary, profile, and shared memory. Chrome runs on that node, so the client machine's Chrome installation may have no bearing on the failure. Verify a remote session with the same node image.

Related Guides