I’m working on a NestJS app that creates PDFs using Puppeteer, but when I try to run it in a Docker container, I keep getting this error:
Error: Browser was not found at the configured executablePath (/usr/bin/google-chrome-stable)
throw new Error(`Browser was not found at the configured executablePath (${launchOptions.executablePath})`);
I’ve tried different approaches like installing Chrome manually in the container, switching to puppeteer-core, and using the official Puppeteer Docker image. No matter what executablePath I set, it always shows the same error pointing to ‘/usr/bin/google-chrome-stable’.
Here’s my Docker setup:
# Using official puppeteer image
FROM ghcr.io/puppeteer/puppeteer:23.3.0
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start:prod"]
And here’s how I initialize the browser in my service:
async initBrowser() {
const launchOptions = {
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
browser: 'chrome',
} as puppeteer.LaunchOptions;
if (this.env !== 'development') {
launchOptions.executablePath = '/usr/bin/google-chrome-stable';
}
this.browserInstance = await puppeteer.launch(launchOptions);
this.pageInstance = await this.browserInstance.newPage();
this.pageInstance.setDefaultTimeout(0);
this.pageInstance.setDefaultNavigationTimeout(0);
}
Using Puppeteer version 23.3.0. Any ideas what might be wrong?
The issue stems from using puppeteer-core behavior while working with the regular puppeteer package. When you’re on the official Puppeteer Docker image, the bundled Chromium binary isn’t located at /usr/bin/google-chrome-stable
- that’s typically where system-installed Chrome would be. The Puppeteer Docker image comes with Chromium pre-installed in a different path that puppeteer automatically detects. Your conditional logic is causing problems because it assumes a standard Chrome installation path that doesn’t exist in this container. Instead of hardcoding the executable path, you should let Puppeteer use its default bundled Chromium by either removing the executablePath entirely in non-development environments, or better yet, check if the file actually exists before setting the path. You can verify this by exec’ing into your container and running which google-chrome-stable
or ls /usr/bin/google-chrome*
to see what’s actually available.
yeah this happens because ur setting executablePath when the puppeteer image already has chromium bundled. just dont set executablePath in docker - let puppeteer find it automatically. the path /usr/bin/google-chrome-stable
doesnt exist in that container anyway so thats why its failing
I ran into this exact issue a few months back and the problem is actually in your launch configuration logic. When you’re using the official Puppeteer Docker image, Chrome is already bundled and Puppeteer knows where to find it automatically. By explicitly setting the executablePath to ‘/usr/bin/google-chrome-stable’, you’re overriding Puppeteer’s built-in detection. The solution is to remove the executablePath assignment entirely when running in Docker. The official Puppeteer image installs Chrome in a different location than what you’re specifying, and Puppeteer’s internal logic handles the path resolution correctly when you don’t interfere with it. Try modifying your initBrowser method to not set executablePath at all when running in production/Docker environment, or only set it when you’re certain about the actual Chrome installation path in your specific container.