Playwright Lambda Layer Errors
Common errors and how to fix them (or avoid them entirely)
Error: Executable doesn't exist
browserType.launch: Executable doesn't exist at /var/task/node_modules/playwright/.local-browsers/chromium-xxx/chrome-linux/chrome
# Or:
Error: Failed to launch the browser process!
/var/task/node_modules/playwright-core/.local-browsers/chromium-xxx/chrome-linux/chrome:
error while loading shared libraries: libnss3.so: cannot open shared object fileWhy This Happens
Playwright downloads browser binaries during npm install, but Lambda deployment packages don't include these binaries or the required system libraries.
Traditional Fix
// Use playwright-core + separate Chromium
npm install playwright-core @sparticuz/chromium
// Then in your code:
const chromium = require('@sparticuz/chromium');
const { chromium: playwright } = require('playwright-core');
const browser = await playwright.launch({
args: chromium.args,
executablePath: await chromium.executablePath(),
headless: chromium.headless,
});This requires careful version matching between playwright-core and @sparticuz/chromium.
Error: Missing System Libraries
error while loading shared libraries: libatk-1.0.so.0: cannot open shared object file
error while loading shared libraries: libcups.so.2: cannot open shared object file
error while loading shared libraries: libdrm.so.2: cannot open shared object file
error while loading shared libraries: libgbm.so.1: cannot open shared object file
error while loading shared libraries: libgtk-3.so.0: cannot open shared object file
error while loading shared libraries: libxkbcommon.so.0: cannot open shared object fileWhy This Happens
Lambda's Amazon Linux 2 runtime is missing GUI libraries that Chrome needs. Even headless Chrome requires many of these libraries.
Traditional Fix
Create a Lambda Layer with the required libraries, or use a pre-built layer:
# In your SAM template or CloudFormation:
Layers:
- arn:aws:lambda:us-east-1:764866452798:layer:chrome-aws-lambda:31
# Or build your own layer with required .so files:
# libnss3, libatk-1.0, libatk-bridge-2.0, libcups, libdrm,
# libgbm, libgtk-3, libxcomposite, libxdamage, libxfixes,
# libxkbcommon, libxrandr, libasound, etc.Layer ARNs change frequently and vary by region. Keeping these updated is ongoing work.
Error: Protocol Timeout
browserType.launch: Protocol error (Browser.getVersion): Browser closed.
==================== Browser output: ====================
[0101/000000.000000:ERROR:zygote_host_impl_linux.cc(100)]
Running as root without --no-sandbox is not supported.
# Or:
Timeout 30000ms exceeded during browserType.launch.Why This Happens
Chrome needs specific flags to run in Lambda's restricted environment. Missing flags = immediate crash or timeout.
Traditional Fix
const browser = await playwright.launch({
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--no-first-run',
'--no-zygote',
'--single-process', // Important for Lambda
'--disable-extensions',
],
headless: true,
});Error: Out of Memory
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
# Or:
Runtime exited with error: signal: killed
# Or:
Task timed out after 30.00 secondsWhy This Happens
Chromium needs 500MB-1GB+ of RAM. Lambda defaults to 128MB. Even with more memory, Chrome can leak and accumulate over invocations if the container is reused.
Traditional Fix
# In your Lambda configuration:
MemorySize: 2048 # At least 1536MB recommended
# And always close the browser:
try {
const browser = await playwright.launch(...);
const page = await browser.newPage();
// ... do work
} finally {
await browser.close(); // Critical!
}The Pattern You're Fighting
Every Playwright-on-Lambda setup follows this painful cycle:
- Install playwright-core + @sparticuz/chromium
- Add a Lambda Layer with system libraries
- Configure browser launch args
- Bump memory to 1536MB+
- Deploy, test, hit a new error
- Debug for hours, fix, repeat
- Three months later: @sparticuz/chromium updates, things break
- Repeat from step 1
Alternative: Skip the Layer Dance
Instead of managing Playwright binaries, layers, and Chrome processes, make an HTTP call:
// No playwright, no chromium, no layers, no memory issues
export async function handler(event) {
const response = await fetch("https://api.riddledc.com/v1/run", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.RIDDLE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ url: event.url })
});
return {
statusCode: 200,
body: Buffer.from(await response.arrayBuffer()).toString("base64"),
isBase64Encoded: true
};
}
// Lambda config: 128MB memory, 30s timeout
// Dependencies: none (fetch is built into Node 18+)Done Fighting Lambda Layers?
Get screenshots with a simple API call. No Chromium required.