ScreenshotNeo

BlogHow-to

How to Fix Chromium Symbol Lookup Errors with Puppeteer on Ubuntu

Diagnose Puppeteer Chromium symbol lookup errors on Ubuntu by checking the active binary, shared libraries, browser versions, architecture, and sandbox.

By the ScreenshotNeo team30 September 20269 min read

How to Fix Chromium Symbol Lookup Errors with Puppeteer on Ubuntu

A Puppeteer launch failure such as symbol lookup error: ... undefined symbol: snd_device_name_get_hint, version ALSA_0.9 means the Chromium executable could not resolve a symbol from a shared library at startup. Treat it as a binary and runtime-library compatibility problem on the target host. The message does not, by itself, prove that one particular Ubuntu package is wrong.

The reliable fix is to identify the exact executable Puppeteer launches, record the host and browser versions, inspect that executable’s dependencies, then repair only the packages or browser build that the evidence points to. The same process applies to other dynamic-linker errors, including missing symbols from NSS, GTK, GLib, or C++ libraries.

What the error means

Linux programs such as Chromium are dynamically linked. At launch, the loader maps shared objects such as ALSA, libc, libstdc++, GTK, and font libraries into the process and resolves the symbols the binary expects. A message containing undefined symbol means a library was found but did not provide the required symbol version, or that an incompatible library was selected first. That differs from an error saying a shared object file is missing.

For the commonly reported ALSA message, Chromium requested snd_device_name_get_hint with the ALSA_0.9 symbol version. Possible causes include an incomplete runtime, an unexpected library search path, a browser built for a different distribution or architecture, or a mismatch between an older downloaded Chromium and the current Ubuntu system. You need the executable path and library-resolution evidence before choosing a repair.

1. Capture the environment before changing it

Run these commands in the same account, container, virtual machine, or CI image where Puppeteer fails:

Trace the executable Puppeteer launches before changing packages.
Trace the executable Puppeteer launches before changing packages.
node --version
npm ls puppeteer puppeteer-core --depth=0
. /etc/os-release && printf '%s %s\n' "$ID" "$VERSION_ID"
uname -m
which google-chrome || true
which chromium || true
which chromium-browser || true

Record the complete launch error, not only the final line. Also record whether the application uses puppeteer (which manages a browser download) or puppeteer-core (which expects you to provide a browser), and whether your code sets executablePath. A path under an old .local-chromium directory is especially important: it may be a legacy browser that is no longer the browser your current Puppeteer version expects.

Make the path explicit in a small diagnostic script. This avoids running ldd against a system Chromium while Puppeteer is actually starting a different file.

const puppeteer = require('puppeteer');

(async () => {
  const executablePath = puppeteer.executablePath();
  console.log({
    puppeteerVersion: require('puppeteer/package.json').version,
    executablePath
  });
})();

For puppeteer-core, print the value from your configuration instead:

const puppeteer = require('puppeteer-core');
const executablePath = process.env.CHROME_PATH;
if (!executablePath) throw new Error('Set CHROME_PATH to the browser Puppeteer launches');
console.log({ puppeteerVersion: require('puppeteer-core/package.json').version, executablePath });

2. Inspect the active Chromium dependencies

Puppeteer’s Linux troubleshooting guidance recommends checking unresolved dependencies with ldd chrome | grep not. Adapt that command to the actual executable path:

CHROME='/absolute/path/from-the-diagnostic-script/chrome'
ldd "$CHROME" | grep 'not found' || true

Keep the complete output as well:

ldd "$CHROME" > /tmp/chromium-ldd.txt
cat /tmp/chromium-ldd.txt

No lines containing not found is useful, but it does not prove ABI compatibility. An undefined-symbol failure can occur when every library file exists and the wrong version is loaded. Inspect the resolved ALSA library and its exported symbols:

ldd "$CHROME" | grep -i asound
ldconfig -p | grep libasound
readelf -Ws /path/to/libasound.so.2 | grep snd_device_name_get_hint

Use the path printed by ldd for the final command. If the symbol is absent or has an unexpected version, investigate the package and library path on that host rather than adding unrelated flags to Puppeteer.

3. Compare dependencies with Ubuntu’s installed packages

Puppeteer’s Debian and Ubuntu dependency list includes libasound2, libatk-bridge2.0-0, libatk1.0-0, libc6, libcairo2, libcups2, libdbus-1-3, libexpat1, libfontconfig1, libgbm1, libgcc1, libglib2.0-0, libgtk-3-0, libnspr4, libnss3, Pango libraries, libstdc++6, X libraries, certificates, fonts, and utility packages. The guide warns that package information can become outdated and links to Chromium’s installer dependency manifest, so validate names against your Ubuntu release before installing anything.

First query the relevant packages:

dpkg-query -W -f='${Package}\t${Version}\t${Status}\n' \
  libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 \
  libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc-s1 libglib2.0-0 \
  libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 \
  libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxdamage1 \
  libxext6 libxfixes3 libxrandr2 ca-certificates fonts-liberation || true

If ldd identifies a missing object, install or repair the package that owns that object for your Ubuntu release. For example, use apt-file or the package search for the exact filename, then run:

sudo apt-get update
sudo apt-get install --reinstall PACKAGE_NAME

Do not blindly install a large community package list. A workaround that changes many libraries and adds --no-sandbox cannot show which step fixed the linker failure, and it may leave the host harder to maintain.

4. Check browser, distribution, and architecture compatibility

Issue reports for this exact ALSA symbol error have included a browser under an old .local-chromium path. In that report, a Puppeteer maintainer described the system as apparently incompatible with prebuilt Chromium binaries and requested a current reproduction containing the Linux distribution, version, and CPU architecture. That is useful diagnostic guidance for the report; it is not a universal diagnosis for every Ubuntu installation. See the Puppeteer issue discussion.

Check all three compatibility dimensions:

  1. Distribution and release: compare /etc/os-release with the browser build’s supported environment and the current Chromium dependency manifest.
  2. Architecture: compare uname -m with file "$CHROME". A browser built for a different architecture cannot be repaired by adding an unrelated Ubuntu package.
  3. Browser generation: compare the installed Puppeteer version and browser revision. Current Puppeteer releases use Chrome for Testing rather than the legacy Chromium download used by older setups; verify release-specific behavior in the current documentation.
file "$CHROME"
strings "$CHROME" | grep -E 'Chrome/[0-9]+|Chromium/[0-9]+' | head
npm view puppeteer version

After upgrading, remove an obsolete browser only when you have confirmed which executable the application uses and have a rollback path. A system-installed Chromium may work on one host and fail on another; choosing it is an environment-specific compatibility decision, not a guaranteed fix.

5. Check library search paths and symbol versions

If all expected files are installed but the symbol remains unresolved, inspect environment overrides and loader diagnostics:

env | grep -E '^(LD_LIBRARY_PATH|LD_PRELOAD)=' || true
LD_DEBUG=libs "$CHROME" --version 2> /tmp/chromium-loader.log || true
sed -n '1,160p' /tmp/chromium-loader.log

An unexpected LD_LIBRARY_PATH or preload can cause Chromium to select a library from a custom application directory before Ubuntu’s library. Remove the override for a test, or fix the service definition so production and interactive shells use the same library set. Compare the library path shown by LD_DEBUG with ldconfig -p and package metadata. Preserve the error output when opening an upstream issue.

6. Use a minimal Puppeteer reproduction

Once the browser itself passes --version, reduce the launch to a script with no application code:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true
  });
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'domcontentloaded'});
  console.log(await page.title());
  await browser.close();
})().catch(error => {
  console.error(error);
  process.exit(1);
});

If this still fails before a page opens, the problem is in the executable, loader, or host. If it works, compare your application’s launch options, environment variables, user account, container image, and working directory with the minimal script.

Sandbox errors are a separate problem

Do not use --no-sandbox as a general response to a symbol lookup error. Puppeteer’s troubleshooting guide discusses that flag for a different message, No usable sandbox!, and strongly discourages running without the sandbox. Prefer a correctly configured sandboxed browser. Only follow the documented exception when the content is absolutely trusted and your deployment has deliberately accepted the security tradeoff.

A clean capture removes common overlays before rendering the final image.
A clean capture removes common overlays before rendering the final image.

Common errors and fixes

Message or symptom Likely category Evidence-based next step
undefined symbol: snd_device_name_get_hint, version ALSA_0.9 ALSA or browser/host ABI mismatch Identify the active binary, inspect ldd, resolve the loaded libasound version, and compare host architecture and release.
error while loading shared libraries: ... cannot open shared object file Missing runtime library or search path Find the package owning the exact filename for the Ubuntu release, then install or repair that package.
No usable sandbox! Sandbox configuration or permissions Follow Puppeteer’s sandbox guidance; do not assume --no-sandbox fixes linker errors.
Changing packages has no effect Wrong executable Print puppeteer.executablePath() or your explicit executablePath, then run diagnostics against that file.
Works locally, fails in CI or EC2 Different image, architecture, libraries, or user Collect node, Puppeteer, Ubuntu, architecture, browser path, and complete dependency output from the failing host.

Performance, reliability, and maintenance

  • Pin deliberately: keep Puppeteer, the browser revision, and the Ubuntu base image under change control. Upgrade them together and reproduce in a clean environment.
  • Diagnose at startup: log the browser path and versions once per deployment. This prevents a package fix from being applied to an unused binary.
  • Keep images reproducible: install dependencies from the distribution repositories or the browser project’s current manifest, and avoid ad hoc libraries copied from another host.
  • Separate browser failures from page failures: a linker exit happens before navigation. Timeouts, bot checks, blank pages, and consent overlays require different diagnostics after the browser launches.
  • Use a service boundary when appropriate: if your application only needs rendered images or PDFs, an HTTP screenshot service avoids shipping Chromium and its native dependencies in every worker. Measure latency and concurrency for your workload rather than assuming a particular benchmark.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server when you need an image or PDF without maintaining a Puppeteer runtime. One GET request returns PNG, JPEG, WebP, or PDF. The same request can use full-page capture with lazy images, an element selector, dark mode, device presets or a custom viewport, retina scale, custom CSS and JavaScript, clicks, waits, blocked resource types, headers, cookies, user agent, authorization, timezone, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous jobs, bulk capture, and PDF options.

cURL:

curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo documentation for request options and response details. Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and whether the request was billed. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.

Create a free ScreenshotNeo account and start with the 1,000 included screenshots.

Diagnostic checklist

  1. Save the complete linker message.
  2. Print Node.js, Puppeteer, Ubuntu, architecture, and the exact executable path.
  3. Run ldd ACTIVE_BINARY | grep not and save full ldd output.
  4. Inspect the resolved library and symbol version when files exist but a symbol is undefined.
  5. Compare package names with current Ubuntu and Chromium guidance.
  6. Test a current Puppeteer/browser combination in a minimal script.
  7. Keep sandbox troubleshooting separate from linker troubleshooting.
  8. When escalating, include a current minimal reproduction and all environment details.

FAQ

Does reinstalling libasound2 always fix this error?

No. It is a relevant dependency, but the symbol failure can reflect a library-version or browser/host compatibility problem even when the package is installed.

Should I switch to system Chromium?

Only after checking the host and browser compatibility. A system browser can be appropriate, but it is not a universal remedy and changes which executable and release you must maintain.

Can I ignore the error if screenshots work on another server?

No. The hosts may differ in architecture, Ubuntu release, loader paths, or browser revision. Collect diagnostics from the failing host.

Is a screenshot API useful if I need PDFs?

Yes. ScreenshotNeo’s API supports PDF output with paper size, margins, landscape mode, and page ranges, and its MCP server includes capture_pdf.