← Compare to Self-Hosted

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 file

Why 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 file

Why 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 seconds

Why 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:

  1. Install playwright-core + @sparticuz/chromium
  2. Add a Lambda Layer with system libraries
  3. Configure browser launch args
  4. Bump memory to 1536MB+
  5. Deploy, test, hit a new error
  6. Debug for hours, fix, repeat
  7. Three months later: @sparticuz/chromium updates, things break
  8. 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+)
0Layers to manage
128MBLambda memory
0Chrome errors

Done Fighting Lambda Layers?

Get screenshots with a simple API call. No Chromium required.