Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
An Operation not permitted or EACCES error from Puppeteer on AWS Lambda is usually caused by one of four things: incorrect file modes in the deployment package, a browser binary that cannot run in Lambda, an invalid executable path, or Chrome trying to write outside Lambda’s writable /tmp directory. Fix those in that order, then verify that your Chromium build, Puppeteer version, Lambda runtime, and CPU architecture belong together.
Start by identifying the exact failure
Do not treat every launch failure as a permissions problem. Capture the complete CloudWatch error, including the path named in the message. The path and wording usually identify the correct branch:
| Observed message | Most likely cause | First action |
|---|---|---|
EACCES, permission denied, or Operation not permitted on /var/task or /opt |
Deployment files or directories do not have the required read/execute bits. | Correct modes before creating the ZIP or layer and deploy again. |
cannot execute binary file |
The binary targets another CPU architecture or is not a Lambda-compatible build. | Use a build for the function’s x86_64 or arm64 architecture and runtime. |
ENOENT, “cannot find executable,” or a path such as a missing /var/task/bin |
The path is relative, wrong for the selected layer, or the browser was omitted from the package. | Resolve and log an absolute extracted path, then check that it exists. |
error while loading shared libraries: libnss3.so |
The browser’s native libraries do not match the Lambda runtime. | Replace the binary/layer or use a container image that supplies the required libraries. |
| Chrome launches and then reports profile or cache errors | Chrome is writing to the read-only deployed code directory. | Move configuration, cache, and the profile under /tmp. |
| The browser disconnects or times out only after several invocations | Stale processes, temporary-file pressure, or a Puppeteer/Chromium mismatch. | Close the browser in finally, clean temporary data, inspect memory and ephemeral storage, and align versions. |
Log the resolved executable path, the Lambda architecture, and the runtime name during troubleshooting. That turns an ambiguous launch error into a package, path, dependency, or resource diagnosis.
Set Lambda package permissions before deployment
AWS states that the Lambda runtime must be able to read files in the deployment package. Its documented baseline is:
#1 Best Overall
- Ordinary files:
644(rw-r--r--). - Directories and executable files:
755(rwxr-xr-x).
Apply the modes to the unpacked function directory, not to the ZIP file after it has been created:
find lambda-package -type d -exec chmod 755 {} ;
find lambda-package -type f -exec chmod 644 {} ;
chmod 755 lambda-package/bin/chromium
If your browser is extracted at runtime, the file that ultimately launches must still be executable. Recreate the ZIP after changing modes and confirm that the layer or package actually contains the browser files. A correctly chmoded file that was never included in the artifact still produces a missing-executable error.
Use a browser build made for Lambda
A desktop Chrome downloaded by Puppeteer is not a safe Lambda deployment. Puppeteer’s troubleshooting guidance calls out an approximately 50 MB Lambda deployment-package constraint and points developers toward serverless Chromium distributions or layers. The size is an approximate documented constraint, not a guarantee for every packaging method.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
@sparticuz/chromium is a serverless Chromium package that provides extraction and predefined serverless launch arguments. A Lambda layer is another option. A container image gives you the most control over native libraries, while AWS CloudWatch Synthetics provides managed Puppeteer/Chromium combinations for that service. These approaches have different maintenance and packaging costs:
| Approach | Runtime and architecture coverage | Version coupling | Package and startup considerations | Native-library control | Who maintains updates |
|---|---|---|---|---|---|
| Lambda layer | Depends on the layer build; select one matching your runtime and architecture. | Layer Chromium and your Puppeteer version must be kept compatible. | Moves browser bytes out of the function ZIP; extraction and cold-start impact depend on the layer. | Libraries supplied by the layer. | Layer publisher and your deployment process. |
@sparticuz/chromium |
Use the package release intended for your Lambda runtime and architecture. | Pair its Chromium revision with a compatible Puppeteer release. | Browser assets are extracted to /tmp; monitor ephemeral-storage use. |
Package supplies the serverless browser assets and launch arguments. | Package publisher plus your version pinning. |
| Container image | You choose the base image and architecture supported by Lambda. | You control the browser and system-library versions together. | Image size can increase deployment and cold-start time, but avoids ZIP-size constraints. | Highest control: install the required native libraries in the image. | Your team maintains the image. |
| AWS CloudWatch Synthetics runtime | Managed combinations documented by AWS for Synthetics. | AWS runtime updates can introduce breaking changes; test dependency updates. | Managed browser packaging, with service-specific limits and behavior. | AWS controls the runtime libraries. | AWS manages the service runtime; you manage scripts and compatibility checks. |
Pin the browser and Puppeteer versions in deployment, and test the exact Lambda runtime and architecture you use in production. A missing libnss3.so is evidence of an incomplete or incompatible runtime dependency; changing permissions cannot create that library.
Resolve and verify the real executable path
Never assume that ./chromium, /var/bin/chromium, or a path copied from another layer exists in your function. Ask the serverless browser package for its extracted path and pass that absolute value to Puppeteer. Log it and check it before calling launch.
The following CommonJS handler illustrates the important sequence with @sparticuz/chromium and puppeteer-core:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsconst chromium = require('@sparticuz/chromium');
const puppeteer = require('puppeteer-core');
const fs = require('node:fs');
exports.handler = async () => {
process.env.XDG_CONFIG_HOME = '/tmp/.chromium';
process.env.XDG_CACHE_HOME = '/tmp/.chromium';
const executablePath = await chromium.executablePath();
console.log('Chromium executable:', executablePath);
if (!fs.existsSync(executablePath)) {
throw new Error(`Chromium executable does not exist: ${executablePath}`);
}
let browser;
try {
browser = await puppeteer.launch({
executablePath,
args: chromium.args,
headless: true,
userDataDir: '/tmp/.puppeteer-profile'
});
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
return { statusCode: 200, body: await page.title() };
} finally {
if (browser) await browser.close();
}
};
The package’s documented args are a safer starting point than copying flags from an old blog post. Serverless builds commonly need sandbox-related flags such as --no-sandbox and --disable-setuid-sandbox, depending on the image and security model. Add them only when required by your selected build, and remove obsolete flags when upgrading.
Keep every Chrome write under /tmp
Lambda’s deployed code paths, such as /var/task and many layer paths under /opt, should be treated as read-only. Puppeteer documents these environment settings for read-only or containerized environments:
process.env.XDG_CONFIG_HOME = '/tmp/.chromium';
process.env.XDG_CACHE_HOME = '/tmp/.chromium';
Set an explicit writable profile as well:
userDataDir: '/tmp/.puppeteer-profile'
This covers Chromium configuration, cache, cookies, crash data, and profile locks. On warm invocations, a previous profile or extracted browser may remain. Reuse can reduce work, but stale locks and growing artifacts can also cause disconnects. Close the browser in a finally block, remove disposable profiles when you do not need them, and monitor the function’s available ephemeral storage.
Align architecture, runtime, and dependency versions
Lambda functions run on either x86_64 or arm64. The Chromium build must target the same architecture. A binary built for the other architecture commonly fails with cannot execute binary file, even when its mode is 755.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Check these pairings as one unit:
- Lambda runtime (for example, the Node.js runtime family you selected).
- Function architecture:
x86_64orarm64. - Chromium distribution or layer release.
- Puppeteer or
puppeteer-corerelease. - Base image and native libraries, if using a container.
AWS-managed Synthetics runtimes document supported Puppeteer/Chromium combinations and warn that dependency updates can be breaking. Pin versions, rebuild the artifact when changing one component, and run a real invocation after each update. If the error names a shared object, replace or rebuild the runtime dependencies instead of repeatedly changing file modes.
Rank #4
Package and deploy with a repeatable check
- Build on a system that produces the target architecture and runtime artifact.
- Install the serverless Chromium package or select a layer intended for that architecture.
- Run the
findandchmodcommands above on the unpacked package. - List the artifact contents and verify that the browser package, its extraction assets, and your handler are present.
- Deploy the ZIP, layer, or container image.
- Invoke the function and inspect logs for the absolute executable path and the first launch error.
- Confirm that temporary profiles and extracted files are under
/tmp, not beside your handler. - Repeat the invocation to expose warm-container residue, stale processes, and storage growth.
Performance, reliability, and cost considerations
Browser extraction, cold starts, and page loading consume both time and memory. A layer can reduce the function ZIP’s browser payload; a container can avoid ZIP constraints but may increase image size. The best choice depends on whether you need native-library control, how often the function is cold-started, and who will maintain browser updates.
Keep browser lifetime as short as the job requires, close every browser even when navigation fails, and avoid retaining large screenshots or profiles in /tmp across warm invocations. If repeated calls time out, inspect memory allocation, ephemeral-storage availability, and leftover Chromium processes before changing navigation timeouts. More memory may help resource pressure, but it does not repair an invalid mode, path, architecture, or missing library.
Or skip the browser setup
If your goal is a reliable website screenshot rather than running Chromium inside your own Lambda package, ScreenshotNeo provides a website screenshot API and MCP server. It accepts a URL and returns PNG, JPEG, WebP, or PDF. Before capture it accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled.
Only clean shots are billed. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
One request is enough:
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 authentication, formats, and options. The service also supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, 12 device presets and custom viewports, retina scale, PDF paper sizes and page ranges, HTML/CSS rendering, custom JavaScript and CSS, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, ad and tracker blocking, custom headers/cookies/user agents/Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Common screenshot-API parameter names are accepted to ease migration.
Best Value
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to try it without adding a card.
Troubleshooting checklist
- Still seeing EACCES: inspect the exact path in the error, verify directory traversal and executable modes are
755, verify ordinary files are644, rebuild the ZIP, and redeploy. - Path exists locally but not in Lambda: log
await chromium.executablePath()in Lambda and use that value instead of a relative path. libnss3.soor another library is missing: change the Chromium layer/package or move to a container image with the required library; chmod cannot solve a missing dependency.- Works on one architecture only: compare the function architecture with the browser artifact and rebuild for the selected
x86_64orarm64target. - Profile/cache errors: set both XDG paths and
userDataDirunder/tmp. - Warm invocations fail: close the browser in
finally, clean disposable temporary data, and check ephemeral-storage and memory metrics. - Upgrade caused a new launch failure: roll back the Puppeteer/Chromium pair, then upgrade the runtime, browser, and library combination together.
Frequently Asked Questions
Does increasing Lambda memory change file permissions?
No. Memory allocation can relieve resource pressure, but it cannot change deployment-package modes, supply a missing shared library, or make an incompatible binary executable.
Free tools Windows power users keep installed
One-click scans. No signup required.
Can Chromium use the function directory for a persistent profile?
Treat the deployed function and layers as read-only. Put profile, cache, configuration, and extraction data in /tmp; persistence there is limited to the lifetime of the warm execution environment.
Why does the same package work on x86_64 but fail on arm64?
The executable is architecture-specific. A package built for one Lambda architecture must be replaced with a Chromium build and native dependencies built for the other.
Is a Lambda layer always smaller or faster than a container image?
Not necessarily. Layers move browser assets out of the function ZIP, while containers provide more control over libraries. Cold-start and size results depend on the selected artifact, runtime, and workload.
Quick 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.

