Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

ChromeDriver hangs have different fixes depending on where execution stops. First determine whether the stall occurs while creating a session, during a browser command, only when tests run in parallel, or while tearing down. Then compare one test with a parallel run, verify that every session uses a matching Chrome/ChromeDriver pair, isolate drivers and profiles, and make quit() unconditional.

What a “hang” can mean

ChromeDriver is a separate executable that Selenium WebDriver uses to control Chrome. Starting Chrome, servicing WebDriver commands and shutting down the service are all part of the test lifecycle. A test runner that appears frozen may actually be waiting for a worker, a WebDriver call may be waiting for a page, session creation may have failed to return, or Chrome may have closed while the driver process remained.

Record the exact Selenium binding and version, Chrome version, ChromeDriver version, operating system, test framework, and whether the run is local, containerized or on Grid. Historical Selenium reports show that parallel execution, session creation and cleanup can fail in materially different environments; an old issue is not proof that the current release has the same defect.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Locate the exact stage that stops

Add timestamps immediately before and after each lifecycle boundary. The first missing “after” timestamp identifies the class of problem.

  • Session creation: the call to construct a driver never returns, or Chrome starts and exits immediately.
  • Browser command: navigation, a click, script execution or an explicit wait never completes.
  • Parallel coordination: an individual test finishes, but the runner waits forever for another worker.
  • Teardown: the test body ends, yet driver.quit() or the worker process does not return.

Keep the first exception rather than only the final runner timeout. A timeout can be a symptom of a dead worker, a blocked network request or a leaked session.

2. Reproduce with one test, then increase concurrency

  1. Run the smallest affected test by itself, with the same browser and environment.
  2. Run two copies concurrently.
  3. Increase workers gradually until the hang appears.
  4. Repeat once with a fresh temporary workspace and profile.

If the test hangs alone, investigate session startup, browser commands, version pairing and the environment before changing parallel settings. If it passes alone but hangs when overlapped, inspect the runner and shared resources first.

Remove shared WebDriver state

Each concurrently executing test should own one WebDriver session. Do not store a driver in a process-wide static variable, pass one instance between tests, or let one test call quit() on a session another test is using. A safe pattern in Python with pytest is:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

@pytest.fixture
def driver():
    options = Options()
    # Add only options required by your environment.
    instance = webdriver.Chrome(options=options)
    try:
        yield instance
    finally:
        instance.quit()

def test_homepage(driver):
    driver.get("https://example.com")
    assert "Example" in driver.title

The same ownership rule applies in Java, C#, JavaScript and other bindings: create the driver in the test or fixture scope that matches the test’s lifetime, and close it in a guaranteed cleanup hook.

Separate profiles, ports and files

Parallel tests must not point Chrome at the same user-data directory. Shared profiles can lock files or expose one test’s cookies to another. Also check custom remote-debugging ports, downloaded-file directories, screenshots, temporary files and application ports. Let ChromeDriver choose ephemeral ports unless your infrastructure requires fixed values, and generate a unique directory per worker.

Check runner worker behavior

A process-based runner and a thread-based runner do not isolate resources in the same way. Confirm how many workers are actually started, whether a worker is being reused after a failure, and whether the runner waits for a child process that has lost its WebDriver connection. Temporarily set the worker count to one; treat the result as a diagnostic comparison, not as a universal fix.

3. Verify Chrome and ChromeDriver versions

Selenium’s Chrome guidance says that ChromeDriver and the Chrome browser versions should match; a mismatch can make the driver error during startup. Capture the exact versions from the machine or container that runs the test, not from a developer workstation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Check the installed Chrome version and the ChromeDriver binary selected by PATH or Selenium Manager.
  • Record the Selenium binding version and the operating-system image or container tag.
  • On Grid, record the node’s browser and driver versions, not only the client machine’s versions.
  • After an image or browser update, invalidate old driver caches and confirm which executable is being launched.

Do not assume that a historical issue filed against an older Selenium, Chrome or Docker release describes the current release. Reproduce with a deliberately matched set before trying a downgrade.

4. Make teardown unconditional

Call driver.quit() for every session that was successfully created, including tests that fail assertions or raise exceptions. The ChromeDriver lifecycle documentation describes quit() as the operation that terminates the session and its service process.

driver = None
try:
    driver = webdriver.Chrome()
    run_test_steps(driver)
finally:
    if driver is not None:
        driver.quit()

If quitting itself never returns, do not immediately add a force-kill command to production cleanup. First preserve the ChromeDriver verbose log, browser and driver process lists, timestamps, worker identity and the original test exception. A historical Selenium report describes a version-specific case in which quit() did not kill the process as expected; that report is evidence to collect diagnostics, not a general instruction to terminate arbitrary processes.

Prevent cleanup from masking the real failure

Give teardown a bounded timeout in the test runner, record whether the session was created, and report cleanup failures separately from assertion failures. Ensure that only the owner of a session performs its cleanup. In containers, also inspect the container’s PID 1 behavior and whether child processes receive termination signals.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Capture logs and process state

For one reproducible run, retain:

  • ChromeDriver verbose output and the first relevant exception;
  • timestamps around construction, navigation, waits and teardown;
  • Chrome, ChromeDriver, Selenium binding, framework and operating-system versions;
  • worker count, worker identifiers and whether execution is threaded or process-based;
  • local, container or Grid topology, including the node used;
  • process listings before and after the hang, plus open-port and temporary-directory state.

Change one variable at a time. For example, do not simultaneously downgrade Selenium, disable parallelism and add a new Chrome flag; you will not know which change mattered.

Diagnostic matrix

Observation Most useful comparison Next action
Single test hangs while constructing the driver Matched versions; local versus container Inspect startup logs, executable selection, browser launch and environment permissions.
Single test passes; parallel run hangs One worker versus increasing worker counts Remove shared drivers, profiles, ports, files and cross-test teardown.
Navigation or click never returns Same test with command timestamps and explicit wait limits Identify the specific command, page dependency or network condition instead of blaming session startup.
Test body ends; process remains Clean teardown with process snapshots Preserve logs and process state, then investigate the environment or version-specific cleanup behavior.
Only Grid or Docker hangs Local run versus the same image/node configuration Compare node versions, resource limits, session capacity and container process handling.

Common failure patterns and fixes

One global driver shared by all tests

Symptom: commands interleave, one test closes the browser, and another waits for a disconnected session. Fix: move driver creation and cleanup into per-test or per-worker scope.

Shared Chrome profile

Symptom: startup is intermittent or Chrome reports a profile lock only under concurrency. Fix: create a unique temporary profile for each session and delete it after the run.

Unbounded waits mistaken for a driver hang

Symptom: the driver is responsive for some commands but a page load or application condition never occurs. Fix: timestamp the command, use an explicit bounded wait, and capture browser-console or network diagnostics appropriate to your application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Version drift between machines

Symptom: the same suite passes on one node and stalls during startup on another. Fix: print versions in every job, pin the browser image where practical, and verify the driver selected on each node.

Cleanup hides the original error

Symptom: the report contains only a teardown timeout. Fix: preserve the first failure, record whether the driver was created, and report cleanup as a separate event.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability and cost trade-offs

More workers can reduce wall-clock time only while the machine, browser and application can sustain them. Excessive concurrency increases CPU, memory, file-lock and port contention and can make a deterministic test look flaky. Establish a baseline at one worker, then increase until resource pressure or failure appears; choose a stable level rather than the largest possible number.

On Grid or containers, include node startup and network latency in your timestamps. A client-side timeout does not prove that the browser is dead: the node may still be launching Chrome or waiting on a resource. Keep artifacts for one failed run so that a retry does not erase evidence.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your goal is simply to obtain a clean screenshot or PDF rather than exercise a browser through Selenium, ScreenshotNeo provides a single HTTP request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

See the parameter reference in the ScreenshotNeo documentation. cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);

ScreenshotNeo includes full-page and element captures, device presets and custom viewports, retina scale, PDF controls, custom CSS and JavaScript, clicks, selector waits, network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation. It also supports transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. Existing screenshot-API parameter names are accepted to ease migration.

The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

FAQ

Should I always disable parallel execution?

No. Use one worker to establish whether concurrency is involved, then restore parallelism after isolating shared resources and selecting a stable worker count.

Does a stuck Chrome window prove ChromeDriver is hung?

No. The client may be waiting on a page command, a test worker or teardown. Timestamps around each boundary distinguish these cases.

Is killing every ChromeDriver process a safe fix?

No. A process may belong to another test or user. Collect ownership, logs and process state first, then apply environment-specific cleanup deliberately.

Frequently Asked Questions

Should I always disable parallel execution?

No. Use one worker to establish whether concurrency is involved, then restore parallelism after isolating shared resources and selecting a stable worker count.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does a stuck Chrome window prove ChromeDriver is hung?

No. The client may be waiting on a page command, a test worker or teardown. Timestamps around each boundary distinguish these cases.

Is killing every ChromeDriver process a safe fix?

No. A process may belong to another test or user. Collect ownership, logs and process state first, then apply environment-specific cleanup deliberately.

The Bottom Line

Find the stage that stalls, reproduce it with one worker, verify matching versions, isolate every session and make teardown unconditional. Use logs and process state to choose an environment-specific remedy instead of applying a blanket flag or downgrade.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.