shadkamel's avatar

Laravel-PDF with Browsershot Exception on laravel forge

hello, i have used the spatie laravel pdf for generating an invoice that work with browsershot, every thing is working in locale and production (laravel forge), after an hour or maybe two, the pdf generator will crash on production, here is the error:

The command "PATH=$PATH:/usr/local/bin NODE_PATH="/home/forge/sl-trucks.com/releases/67020047/node_modules" "/usr/bin/node" '/home/forge/sl-trucks.com/releases/67020047/vendor/spatie/browsershot/src/../bin/browser.cjs' '-f file:///home/forge/sl-trucks.com/releases/67020047/storage/temp/943269296-0594054001775539573/command.js'" failed. Exit Code: 1(General error) Working directory: /home/forge/sl-trucks.com/releases/67020047/public Output: ================ Error Output: ================ Error: Failed to launch the browser process: Code: 1 stderr: /system.slice/php8.4-fpm.service is not a snap cgroup for tag snap.chromium.chromium TROUBLESHOOTING: https://pptr.dev/troubleshooting at ChildProcess.onClose (/home/forge/sl-trucks.com/releases/67020047/node_modules/@puppeteer/browsers/lib/cjs/launch.js:350:24) at ChildProcess.emit (node:events:531:35) at ChildProcess._handle.onexit (node:internal/child_process:293:12) 

when i run php artisan config:cache it will work again for two house then it will crash again, does any one have a clue how to solve this problem?

here is an example of the controller method:

return Pdf::view('PDF.invoice', compact('invoice'))
            ->format('a4')
            ->landscape()
            ->name("{({$invoice->invoice_no})-{$invoice->created_at->format('Y-m-d')}.pdf")
            ->download();
0 likes
7 replies
LaryAI's avatar
Level 58

Certainly! This is a well-known issue with Puppeteer/Browsershot when used on Forge (or similar shared hosts) because headless Chrome (used for PDF rendering) can sometimes run out of system resources, or its processes don’t get cleaned up. Your problem of "works after config:cache but crashes after some time" is a clue that it’s environmental, not code logic.

Problem Analysis

  • Chrome/Chromium can't start - Error: Failed to launch the browser process.
  • Error mentions:
    /system.slice/php8.4-fpm.service is not a snap cgroup ... 
    
  • Works after php artisan config:cache (possibly temporarily cleans up/stops old processes).
  • Fails after a while (zombie Chrome processes, lack of permissions, or resource leak).

Solution Steps

1. Ensure chromium's dependencies are installed

On Forge you must install all required dependencies for headless Chrome:

SSH to your server and run:

sudo apt-get update
sudo apt-get install -y \
    chromium-browser \
    libappindicator3-1 \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libgbm1 \
    libnspr4 \
    libnss3 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    xdg-utils \
    libu2f-udev \
    libvulkan1 \
    libxss1 \
    fonts-liberation \
    fonts-unfonts-core

Many Chrome errors on Forge are resolved just by this.


2. Set CHROME_PATH in your .env

Tell Browsershot/Puppeteer exactly where Chromium is located:

Add in your .env:

CHROME_PATH="/usr/bin/chromium-browser"

(In newer Ubuntu it may be /usr/bin/chromium -- check with which chromium-browser or which chromium.)


3. Set up Browsershot to use the correct binary

If not already, specify the binary in your PDF/Browsershot config:

use Spatie\Browsershot\Browsershot;

Browsershot::setChromePath(env('CHROME_PATH') ?: '/usr/bin/chromium-browser');

Or directly within your PDF config if package supports it:

return Pdf::view('PDF.invoice', compact('invoice'))
    ->format('a4')
    ->landscape()
    ->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
    ->withBrowsershot(
        fn ($browsershot) => $browsershot->setChromePath(env('CHROME_PATH', '/usr/bin/chromium-browser'))
    )
    ->download();

4. Add Browsershot/Chrome flags (to prevent resource issues)

Often, Chrome needs extra flags when run in Forge/Laravel shared env. For example:

return Pdf::view('PDF.invoice', compact('invoice'))
    ->format('a4')
    ->landscape()
    ->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
    ->withBrowsershot(function ($browsershot) {
        $browsershot
            ->setChromePath(env('CHROME_PATH', '/usr/bin/chromium-browser'))
            ->addChromiumArguments([
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage',
            ]);
    })
    ->download();
  • --no-sandbox and --disable-setuid-sandbox are essential on Forge servers!
  • --disable-dev-shm-usage can help if /dev/shm is too small (typical on Forge).

5. Kill zombie Chromium processes (if leaks persist)

Old Chrome/Chromium processes might accumulate. Consider a (safe) cron job:

# Run every 6 hours
0 */6 * * * pkill -f "(chrome)?(chromium)?(--headless)"

Final Example

Your controller method could look like:

return Pdf::view('PDF.invoice', compact('invoice'))
    ->format('a4')
    ->landscape()
    ->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
    ->withBrowsershot(function ($browsershot) {
        $browsershot
            ->setChromePath(env('CHROME_PATH', '/usr/bin/chromium-browser'))
            ->addChromiumArguments([
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage',
            ]);
    })
    ->download();

Troubleshooting

  • Check for running Chrome/Chromium processes: ps aux | grep chromium
  • Check PHP logs for related errors.
  • Try running a minimal Browsershot test from the command line as forge user.

References


If after all of these you still have issues, provide the output of which chromium-browser and any recent log outputs for help fine-tuning the fix.

shadkamel's avatar

i think browsershot will never work for me.

Jsanwo64's avatar

Best bet would be to use use chatgpt and follow through. And give it every error that you get. I was able to use it twice to get browsershot working on a web app running in forge. Better still you can checkout or use https://github.com/barryvdh/laravel-dompdf

1 like
shadkamel's avatar

thank you for your replay, i used all AI chats for solving this problem but it doesn't helpfull, so i switched to dompdf.

imranbru's avatar
imranbru
Best Answer
Level 4

I know you already switched to dompdf, but if you ever need modern CSS (flexbox/grid) back, here is the actual solution. The AI completely missed the root cause.

The specific error not a snap cgroup happens because recent Ubuntu versions on Forge install Chromium as a Snap package. Snap's strict AppArmor/cgroup confinement blocks it from being executed by daemon services like php-fpm. Running config:cache likely just triggered a worker/FPM restart that temporarily masked the issue before the cgroup restrictions clamped down again.

To fix it permanently, you need to ditch the Snap version entirely and install the native Google Chrome binary.

SSH into Forge and nuke the snap version:

sudo snap remove chromium

Install the native Google Chrome package:

wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install -y google-chrome-stable

Update your PDF generation:

return Pdf::view('PDF.invoice', compact('invoice'))
    ->format('a4')
    ->landscape()
    ->name("{$invoice->invoice_no}-{$invoice->created_at->format('Y-m-d')}.pdf")
    ->withBrowsershot(function ($browsershot) {
        $browsershot->setChromePath('/usr/bin/google-chrome-stable')
                    ->addChromiumArguments(['--no-sandbox', '--disable-setuid-sandbox']);
    })
    ->download();

Dompdf is fine for basic tables, but applying this fix takes 2 minutes and gets Spatie/Browsershot running flawlessly on Forge forever.

1 like
shadkamel's avatar

thanks for your explanation i really appreciate it, it was so clear to me i think it will work fine and it will help other to fix their issues, for the next time i will try all you said, i will replay my feedback on it.

thank you again.

1 like

Please or to participate in this conversation.