Most socket hang up errors from chromium.puppeteer.launch() in Lambda mean that the local Chromium process exited or disconnected while Puppeteer was opening its DevTools WebSocket. They do not, by themselves, prove that the website you wanted to capture rejected the request. Align chrome-aws-lambda with the matching puppeteer-core release, use the package’s launch settings, give the function enough memory, isolate /tmp, and inspect VPC routing separately if the function is VPC-connected.
What the error means
During launch(), Puppeteer starts Chromium and connects to a localhost Chrome DevTools WebSocket. In the failure documented in chrome-aws-lambda issue #207 (opened April 1, 2021), that connection is reset while Chromium is starting, so Node reports Error: socket hang up. This is a browser-process startup or disconnect symptom. It is different from a navigation error that occurs after a browser and page already exist.
First identify the phase. Log whether the exception is thrown by chromium.puppeteer.launch(), by page.goto(), or later during page work. Puppeteer issue #3927 describes browser disconnections during roughly 500 near-simultaneous invocations; that pattern requires separate investigation of process limits, storage, concurrency and cleanup rather than assuming a single networking cause.
1. Record the runtime and exact versions
Before changing flags, add startup logging for the Node.js runtime, Lambda architecture, configured memory, chrome-aws-lambda version, puppeteer-core (or puppeteer) version, and the Chromium revision. Also log the Lambda request ID and whether the error happens during launch or navigation. This distinguishes a compatibility failure from a page or network failure.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
console.log({
node: process.version,
arch: process.arch,
chromeAwsLambda: require('chrome-aws-lambda/package.json').version,
puppeteerCore: require('puppeteer-core/package.json').version,
memoryMb: process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE,
requestId: context.awsRequestId
});
Do not choose the two packages independently. chrome-aws-lambda releases are tied to Puppeteer minor versions and a specific Chromium revision. The project README says its binary is shipped for the latest stable Puppeteer release at the time of publication and requires the corresponding puppeteer-core (or puppeteer) version. Use the repository’s version table when pinning dependencies. One documented legacy pairing is Puppeteer 10.1 with chrome-aws-lambda 10.1 and Chromium revision 884014 (Chrome 92.0.4512.0).
2. Install a matched dependency pair
Why arbitrary upgrades fail
A Puppeteer client expects a compatible DevTools protocol and executable. Updating only puppeteer-core, or packaging a Chromium binary from another release, can make launch fail before a page is created. Lock both versions in your package manifest and deployment artifact, then redeploy the lockfile—not just your source file.
When the legacy package is the problem
chrome-aws-lambda’s compatibility table is historical; its Puppeteer 10.1 entry corresponds to Chrome 92. If your Lambda runtime, architecture or Puppeteer release is newer than that table, test a maintained Chromium package such as sparticuz/chromium or use a Lambda container image. Pin the browser and automation library together and verify the pair in a clean deployment. A legacy package can still be appropriate when you deliberately keep a pinned historical stack.
3. Use the package’s known-good launch shape
Start with the values exposed by chrome-aws-lambda instead of adding flags copied from unrelated environments. The following handler follows the project’s documented fields and closes the browser on every path:
Recommended Free Tools
Rank #2
const chromium = require('chrome-aws-lambda');
exports.handler = async (event, context) => {
let browser;
try {
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true
});
const page = await browser.newPage();
await page.goto(event.url || 'https://example.com', {
waitUntil: 'domcontentloaded'
});
return await page.title();
} finally {
if (browser) await browser.close();
}
};
Keep ignoreHTTPSErrors only if your application needs to visit a site with certificate problems; it does not repair a Chromium process that is exiting. Do not add sandbox, shared-memory or GPU flags as a first reaction. Add one flag only after stderr or an exit code identifies a concrete issue, so you can tell which change helped.
4. Increase Lambda memory and inspect the process exit
The chrome-aws-lambda README says to allocate at least 512 MB and recommends 1600 MB or more. Memory also determines the CPU allocation Lambda gives the function, so a small setting can make Chromium startup slow or unreliable. Set memory in the function configuration, redeploy, and compare launch duration with the timeout.
In CloudWatch, capture Chromium stderr, an exit code if present, configured memory, maximum memory used and remaining duration. A process killed for memory pressure or a timeout during startup can appear to Puppeteer as a WebSocket reset. If the log ends near the timeout, increase the timeout as well as memory; otherwise you may simply be hiding the same failure behind a longer wait.
- Out-of-memory or abrupt exit: raise memory, reduce concurrent pages and avoid retaining page or browser objects between invocations.
- Timeout during launch: raise timeout after confirming the package can start, then investigate cold-start size and CPU allocation.
- Immediate exit with no page: recheck the executable path, architecture and package pairing.
5. Treat /tmp as disposable
Lambda may reuse an execution environment, so files written to /tmp can remain between requests. If you need a profile, create a unique directory for the invocation and pass it as userDataDir. Always close the browser in a finally block. When reused environments accumulate profile data or core dumps, remove stale files before launch after confirming the logs show that accumulation.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
const fs = require('fs/promises');
const path = require('path');
const profile = path.join('/tmp', `profile-${process.env.AWS_REQUEST_ID || Date.now()}`);
await fs.mkdir(profile, { recursive: true });
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: chromium.headless,
userDataDir: profile
});
Do not treat a persistent directory as proof of the root cause. Issue #3927’s report of disconnections under high concurrency and a persistent /tmp/puppeteer_data directory is evidence to inspect storage and concurrency, not a universal explanation for every hang-up.
6. Separate VPC networking from browser startup
A launch-time localhost WebSocket reset points first to Chromium. Networking can still create a second failure when the function is attached to a VPC or the target page immediately makes outbound requests. AWS states that VPC-connected functions send all outbound requests through the VPC and need a NAT gateway for internet access.
Check the complete VPC path
- Confirm the selected private subnet’s route table sends internet-bound traffic to a working NAT gateway.
- Check security-group egress and ingress rules, subnet network ACLs, DNS settings and ENI quotas.
- Verify the function’s IAM permissions for the networking resources used by its deployment.
- For intermittent TCP or UDP failures, ensure network ACLs allow ephemeral ports 1024–65535 as AWS documents.
Run a minimal launch test and a separate navigation test. If launch fails before any page request, fix the local process, binary or resources first. If launch succeeds but navigation times out only inside the VPC, follow the route, DNS and firewall path instead of changing Chromium flags.
7. Control concurrency and cleanup
Every invocation can create a Chromium process, temporary files and several child processes. Limit reserved or event-source concurrency while diagnosing, and avoid opening multiple pages when one will do. Close pages and browsers promptly. For burst workloads, test a smaller batch, watch maximum memory and inspect whether failures correlate with concurrent launches. A successful single invocation does not establish that hundreds of simultaneous launches will fit the function’s memory, process and temporary-storage limits.
8. A diagnostic decision tree
- Does the stack trace name
launch()? Log versions, architecture, memory and Chromium stderr. If the trace namesgoto()or a later operation, investigate navigation, DNS, TLS and the target site separately. - Are the browser packages matched? Replace independently selected versions with the pair from the chrome-aws-lambda table, or test a maintained package for a current runtime.
- Is memory at least 512 MB? Increase toward the project’s 1600 MB recommendation and compare startup metrics.
- Is
/tmpgrowing across warm invocations? Use an isolated profile, clean confirmed stale data and verify that every path closes the browser. - Is the function in a VPC? Validate NAT, routes, DNS, security groups, NACLs, IAM and ENI capacity. Do not infer a VPC cause from a localhost reset alone.
- Does the legacy stack remain incompatible? Test
sparticuz/chromiumor a container image with pinned, matching versions.
Common symptoms and fixes
| Symptom | Most useful first check | Fix to test |
|---|---|---|
Hang-up immediately in launch() |
Package versions, executable path, architecture and Chromium stderr | Install the documented matching pair and use chromium.executablePath |
| Works locally, fails only in Lambda | Memory, CPU allocation, binary packaging and runtime architecture | Use at least 512 MB, preferably 1600 MB or more, and redeploy a clean artifact |
| Fails after several warm requests | /tmp contents, profile reuse and missing cleanup |
Use a unique profile, remove confirmed stale files and close in finally |
| Launch succeeds; page navigation times out in a VPC | Subnet route, NAT gateway, DNS, security group and NACL | Repair outbound VPC routing; allow required ephemeral ports |
| Only high-concurrency runs disconnect | Concurrent processes, memory, timeout and temporary storage | Throttle concurrency, raise resources and isolate profiles |
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server, so your Lambda function does not have to package or start Chromium. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info and capture_pdf—let Claude, Cursor and other MCP clients request captures.
One GET request returns PNG, JPEG, WebP or a PDF. See the ScreenshotNeo API documentation for all options, including full-page lazy-image loading, CSS-selector element capture, device presets, retina scale, PDF margins and page ranges, custom CSS/JavaScript, clicks, waits, request blocking, headers, cookies, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs and usage reporting.
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account to try the call without deploying Chromium.
Frequently asked questions
Does socket hang up prove the website blocked my Lambda IP?
No. In the documented launch failure, the reset occurs on the localhost DevTools connection while Chromium starts. A target-site block is a separate possibility only after the browser launches and navigation begins.
Should I add --no-sandbox immediately?
No. Begin with chromium.args and the package launch values. Add a flag only when logs identify a specific sandbox, shared-memory, GPU or process problem.
Best Value
Is 512 MB enough?
It is the project’s stated minimum. The README recommends 1600 MB or more because additional memory also provides more CPU, which can improve browser startup reliability.
Should I reuse one browser between invocations?
Warm reuse can reduce startup work, but it also increases exposure to stale profiles and disconnected processes. Use strict cleanup and health checks; if reliability matters more than cold-start time, launch and close within each invocation while diagnosing.
Frequently Asked Questions
Can a VPC cause this exact launch error?
It can cause related outbound failures, but a reset during launch is primarily a local Chromium-process symptom. Verify VPC routing separately, especially when navigation fails after launch.
When should I migrate away from chrome-aws-lambda?
Consider migration when your runtime, architecture or Puppeteer version is newer than the legacy compatibility table. Test a maintained package such as sparticuz/chromium or a container image with pinned versions.
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.




