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.

There is no single Docker flag that fixes every Chrome Headless “unknown error.” The phrase is a symptom, not a diagnosis: Chrome may be failing to launch, the automation client may be unable to connect, a renderer may be crashing, or the container may lack a needed resource. Capture the full browser output and identify the exact versions and runtime conditions first, then follow the branch that matches the evidence.

What to collect before changing the container

Do not start by adding several flags at once. That can hide the original failure, weaken the browser’s security, or make a later failure harder to understand. Record the details below from the same run that produces the error:

  • The complete application log and Chrome/Chromium standard output and error, including the process exit code.
  • The actual browser executable path and its version; the ChromeDriver version, if used; and the automation library and version.
  • The Docker image name and tag, CPU architecture, effective user inside the container, and the container’s security profile.
  • Container memory limits and the size of /dev/shm.
  • The headless mode and every browser launch argument.
  • Whether the browser process exits, stays alive without connecting, or connects before the failure occurs.

“Unknown error” alone does not distinguish among launch, protocol, renderer, graphics, and resource failures. A wrapper may report that phrase after Chrome has already exited; the browser’s own stderr and exit status are often more useful than the wrapper’s summary.

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.

Capture Chrome’s own diagnostic output

On Linux, Chromium documents enabling browser logging to stderr with --log-level=0 --enable-logging=stderr. Newer builds that use VLOG output may also need --v=1. Add these temporarily to the existing launch arguments and preserve the resulting output. Do not replace the rest of your known-good launch configuration during this first capture.

google-chrome --headless --log-level=0 --enable-logging=stderr --v=1 --dump-dom https://example.com

The executable may be named chromium or chromium-browser instead of google-chrome. Use the binary actually installed in the image. The command is a diagnostic probe: it asks Chrome to load a page and print its DOM, and does not reproduce every automation-library workflow.

Confirm Chrome, driver, and headless-mode compatibility

Check the binaries and versions from the image that actually runs the job—not only from a development machine or a build stage. For an image with a shell and the relevant binaries on PATH, a quick inventory looks like this:

docker run --rm YOUR_IMAGE sh -lc 'id; command -v google-chrome || command -v chromium || command -v chromium-browser; google-chrome --version 2>/dev/null || chromium --version 2>/dev/null || chromium-browser --version 2>/dev/null; chromedriver --version 2>/dev/null || true'

Replace YOUR_IMAGE with the image and tag from the failing deployment. If the image has no shell or those executable names are absent, inspect it using the commands and tools appropriate to that image. Record the automation library version separately; it may select launch arguments or a headless implementation on your behalf.

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

Do not rely on the old Headless flag without checking the build

Chromium’s Headless documentation says that, as of M132, old Headless shell functionality is no longer part of the Chrome binary, so --headless=old has no effect. Users who depend on that old implementation should migrate to chrome-headless-shell. The documentation also describes precompiled headless_shell binaries through Chrome for Testing since M118. These are version-sensitive details: verify the release and packaging you actually use rather than copying a launch recipe written for an older Chrome.

For example, Puppeteer’s documented headless: 'shell' option is relevant when deliberately using the shell implementation; it is not a universal fix for Chrome launch errors. Match the browser, driver where applicable, and automation library to their current compatibility guidance. If you use a library that manages its own browser, find out which executable it launches before changing a separately installed system Chrome.

Check the container user and sandbox before disabling security

Chrome’s sandbox is a security boundary, not an incidental performance setting. Chrome Developers documentation says --no-sandbox is not needed when the user is properly set up in the container. First establish which user launches the browser and which security profile the runtime applies. Running as root, using a restrictive or incompatible runtime profile, and having an incorrectly configured unprivileged account are different conditions and should not be collapsed into one workaround.

docker exec YOUR_CONTAINER id
docker inspect --format '{{.Config.User}}' YOUR_CONTAINER

The first command reports the effective user for an exec session; the second shows the configured container user, which may be empty when the image does not specify one. Confirm the actual browser process user too if your entrypoint or application changes identity before launch. For a controlled comparison, use a properly configured unprivileged user and the intended container security profile, then check whether the launch succeeds.

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

Do not reflexively add --no-sandbox to production arguments just because it appears in an old Docker example. If a temporary diagnostic run requires changing sandbox settings, treat that as a security-sensitive experiment, not as proof that disabling the sandbox is the right deployment fix. Restore the intended security controls and resolve the user, kernel/runtime, or profile problem indicated by the evidence. The chromedp headless-shell image README demonstrates an unprivileged nobody user with a seccomp profile as one image-specific setup, not a universal recipe for all browser images.

Investigate memory and shared memory when the failure points there

Check both the container’s overall memory limit and its shared-memory mount. They are related operational constraints but are not interchangeable settings. A container can have available memory while its shared-memory mount remains small, or the reverse. Inspect the values from inside the running container:

docker exec YOUR_CONTAINER sh -lc 'df -h /dev/shm; cat /proc/meminfo | head'

Also inspect the deployment configuration for its memory limit and any shared-memory setting. If the browser exits under load, a renderer crashes, or the logs point to a memory or shared-memory problem, compare the failure with those limits and test one change at a time.

Use --shm-size as a targeted test, not a magic default

The chromedp headless-shell image maintainer specifically links BUS_ADRERR crashes in that image to insufficient shared memory and gives --shm-size 2G as an example. For a Docker run using that image, the corresponding kind of test is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
docker run --rm --shm-size=2G YOUR_IMAGE

Adapt the command to the image’s actual entrypoint and arguments. The 2G value is an example for that image and crash context, not a required allocation for every Chrome container. Do not increase shared memory merely because an automation wrapper says “unknown error”; first look for a matching crash signature and check the container’s overall resource limits.

Separate browser launch failures from connection failures

If Chrome starts and remains running but the automation client reports that it cannot connect, investigate the DevTools protocol path rather than treating the event as a launch failure. Check the client’s configured endpoint, the browser’s remote-debugging arguments, and whether the port or endpoint is reachable from the client’s network namespace. A browser that is reachable from inside its own container may not be reachable from another container or from the host without the expected networking configuration.

For a manual inspection, Chromium documents starting headless Chrome with a remote debugging port and then inspecting it through chrome://inspect/:

google-chrome --headless --remote-debugging-port=9222 https://example.com

This is an inspection approach, not a recommendation to expose a debugging port publicly. Keep debugging access limited to the environment that needs it, and remove temporary debugging configuration when the investigation is complete. If Chrome exits before it can listen, return to the stderr, exit-code, version, sandbox, and resource branches rather than repeatedly changing the client endpoint.

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

Follow graphics symptoms separately

Only investigate GPU or graphics configuration when the workload or logs point to rendering, WebGL, a graphics driver, or a GPU-process failure. Headless GPU behavior depends on the environment. Chromium’s GPU documentation says --enable-gpu disables forced software rendering; it also notes that Linux’s default OpenGL driver detection requires an X display and that forcing Vulkan has worked in some Linux configurations. Those are specialized options, not general Chrome startup fixes.

Best Value
Docker Container Linux Devops Programming Coding T-Shirt
  • Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
  • Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem

For a rendering-specific failure, first establish whether the job needs GPU-backed rendering and whether the container has the relevant driver and display/runtime setup. Change one graphics setting at a time and compare the browser’s diagnostic output. Do not add GPU flags to solve a failure that occurs before Chrome launches or before a client connects; they address a different failure family.

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

Check process cleanup if browser children accumulate

If Chrome runs but child processes remain after jobs finish, or the container accumulates zombies, inspect how the container’s PID 1 handles child-process reaping and how the entrypoint manages Chrome’s process tree. The chromedp image maintainer notes possible zombie processes and recommends an init process; its example uses --init with Podman and also points to tini or dumb-init for older Docker guidance. Confirm your runtime and entrypoint before selecting a mechanism. An init setting will not repair a browser that fails to launch because of a version mismatch or missing shared memory.

Use crash evidence for failures that remain unexplained

When Chrome crashes without a clear message, preserve the exact build information, complete logs, exit status, minimal reproduction, and the container configuration used for that run. Chromium’s Linux troubleshooting guidance documents ulimit -c unlimited as a way to enable core dumps for Chrome processes, while noting that sandboxed processes may be exceptions:

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

Run it in the same process environment that starts Chrome, and verify where that environment writes core files and whether the runtime permits them. A missing core file does not establish that Chrome did not crash. Crash artifacts are most useful when paired with the browser build, automation-library version, architecture, user, security profile, and resource settings; without that context, it is difficult to distinguish a reproducible browser problem from a container-specific one.

A practical triage order

  1. Capture: preserve the full wrapper and Chrome output plus the exit status. Enable Chrome stderr logging if needed.
  2. Inventory: record the image/tag, architecture, executable, Chrome and driver versions, automation library version, headless mode, and launch arguments.
  3. Classify: determine whether Chrome exits before launch completes, the client cannot connect to a running browser, rendering fails, or processes accumulate.
  4. Match the condition: check compatibility for version or headless-mode symptoms; user and security settings for sandbox symptoms; memory and /dev/shm for resource evidence; graphics configuration for GPU evidence; and process reaping for zombie symptoms.
  5. Change one thing: rerun the same workload, preserve the new output, and compare the result. Keep only changes supported by the observed failure.

If none of these branches fits, the title-level phrase is not enough to determine a root cause. Share the exact error text and the collected environment details with the browser, driver, library, or image maintainers appropriate to the failing layer.

Or skip the browser setup

If your goal is to capture a website rather than debug a browser container you control, ScreenshotNeo provides a screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF. Here is the one-call cURL example, using a URL you can replace with your target:

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

See the ScreenshotNeo API documentation for request options and setup. Before capture, it accepts the consent banner like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

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

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

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.