If Playwright reports a permission error while saving a screenshot in Docker, first determine whether it failed to write the image or failed earlier while launching Chromium. For a write failure, check the process UID/GID, the destination directory and bind-mount permissions, and whether HOME is writable. For a launch failure, investigate Chromium sandboxing, browser-version alignment, and shared memory instead; those are separate from permission to save a file.
Identify which operation failed
Read the complete error, including the path named in it, and note whether it appeared during browser launch or at page.screenshot(). A denial naming an output path points first to filesystem access. If Chromium never starts, a screenshot-file permission fix will not address the underlying problem.
As an Amazon Associate I earn from qualifying purchases.
Playwright resolves a relative screenshot filename against the workspace root. If a filename is omitted, the CLI or API may use an output directory, so make the destination explicit while diagnosing the problem. See Playwright’s screenshot documentation.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Check the container user and output mount
The process needs write permission on the destination directory, not merely permission to run Playwright. Check the effective user and numeric IDs from inside the same container and execution context that runs the test:
#1 Best Overall
id
printf 'HOME=%sn' "$HOME"
ls -ld /out
Compare the reported UID/GID with the output directory’s owner and mode. If /out is a bind mount, inspect the host directory too: the container identity, host ownership, and Docker or orchestrator identity mapping together determine whether the process can write and whether the host can later read the file.
Do not assume that running as root inside a container guarantees the host will see files with useful ownership, or that a host user’s numeric IDs match an image’s default user. Use the identity actually assigned in your environment.
Make the output directory and HOME writable
Check both the screenshot destination and HOME. Browser profiles, npm, and browser-related caches may need to write under HOME, even when the screenshot itself goes elsewhere. Docker’s Playwright Hardened Images guide documents this requirement for its image and illustrates a run with the host UID/GID, an output mount at /out, and HOME=/tmp.
Rank #2
For an image and workflow where those paths are appropriate, the pattern looks like this:
docker run --rm
--user "$(id -u):$(id -g)"
-e HOME=/tmp
-v "$PWD/output:/out"
your-playwright-image
node screenshot.js
Adapt the image name, command, mount path, and home directory to your setup. Do not copy the UID/GID mechanically if an orchestrator assigns a different identity, or assume that /tmp is the right home for every image. Ensure the mounted output directory exists and is writable by the selected user.
Separate Chromium sandbox errors from file permissions
In the upstream Playwright Docker image, browsers run as root by default. Playwright’s Docker documentation states that Chromium’s sandbox is unavailable with root. For trusted end-to-end test targets, the documentation says root may be acceptable. For crawling or other untrusted pages, it recommends a separate user and a seccomp profile that permits the user-namespace operations Chromium needs.
Rank #3
That browser sandbox restriction concerns how Chromium starts and isolates pages; it does not grant or deny write access to a PNG or JPEG path. Choose the execution model based on the trust level of the pages you load, then diagnose output permissions independently. Do not treat disabling security protections as a general fix for a path-specific write denial.
Recommended Free Tools
Check image and Playwright version alignment, then shared memory
Use a Playwright Docker image compatible with the Playwright version installed by the project and tests. Playwright warns that a mismatch can prevent it from locating browser executables; consult the current Docker guidance and pin compatible versions rather than relying on an untracked image tag.
A Chromium crash can also be caused by insufficient shared memory. The Playwright Docker guide recommends --ipc=host for Chromium because it may otherwise run out of memory and crash. A crash is not evidence that the output directory is unwritable. Apply this option only where it is appropriate for your container security and deployment setup.
Retest with one explicit screenshot path
Once the user, mount, and browser setup are understood, use a minimal script that saves to the intended mounted directory:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: '/out/example.png' });
} finally {
await browser.close();
}
})();
Run it with the same user and mount configuration as the failing job. Confirm that /out/example.png exists inside the container, then inspect its owner and permissions from the host. If the container writes it but the host cannot access it, focus on ownership mapping and mount behavior rather than Playwright’s screenshot API.
Choose a container pattern that fits the workload
| Situation | What to account for |
|---|---|
| Trusted end-to-end test pages | The upstream Playwright image runs as root by default; its documentation says root may be acceptable for trusted tests, but Chromium’s sandbox is unavailable in that mode. |
| Crawling or other untrusted pages | Use a separate user and the suitable seccomp configuration described in Playwright’s Docker documentation to support Chromium’s user-namespace needs. |
| Non-root execution with a mounted output directory | Make the mount writable by the effective container UID/GID, and verify host-side ownership expectations. |
| Docker Hardened Images for Playwright | Docker documents its Playwright image as non-root by default, with UID 65532, and provides its own writable-mount and HOME example. These defaults are specific to that image. |
The upstream Playwright and Docker Hardened Images have different user and filesystem assumptions. Follow the documentation for the image actually in use rather than transferring a fix from one image to the other.
Best Value
- 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
Common errors and targeted fixes
- Permission denied naming the screenshot path: Check the process UID/GID, directory ownership and mode, and bind-mount access. Write to an explicit path in a directory the process can modify.
- Browser profile or cache cannot be created: Check whether
HOMEis writable for the effective user; the screenshot mount may be fine while a cache or profile path is not. - Chromium launch or sandbox error under root: Treat this as a launch configuration issue. For untrusted pages, follow Playwright’s separate-user and seccomp guidance rather than confusing sandboxing with image-file permissions.
- Browser executable cannot be located: Align the project Playwright package and Docker image versions, then follow the matching image documentation.
- Chromium crashes without a path denial: Check shared-memory configuration; Playwright recommends
--ipc=hostfor Chromium in Docker. - Container can create the file but host cannot use it: Inspect the resulting owner and mode and review host/container identity mapping and mount behavior.
Or skip the browser setup
If your task is to capture a website rather than run Playwright inside your own container, ScreenshotNeo can return a screenshot from one GET request. This cURL example saves the response as WebP; replace the URL with the page you need. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo and start with 1,000 free screenshots a month, no card required.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsQuick Recap
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.




