srbhr/Resume-Matcher · critical · PDFRenderError

Playwright browser executable is missing, and no system Chro

Error message

Playwright browser executable is missing, and no system Chrome/Edge installation was found. Install Playwright browsers or install Chrome/Edge.

What it means

_launch_browser first tries playwright.chromium.launch(); if Playwright raises an 'Executable doesn't exist' error (browsers not installed), it looks for a system Chrome/Edge via _find_chromium_executable(). When neither exists it raises PDFRenderError with this message.

Source

Thrown at apps/backend/app/pdf.py:131

            Path(os.path.expanduser("~/.local/share/flatpak/exports/bin/com.google.Chrome")),
            Path(os.path.expanduser("~/.local/share/flatpak/exports/bin/org.chromium.Chromium")),
        ]

    for candidate in candidates:
        if candidate.exists():
            return str(candidate)
    return None


async def _launch_browser(playwright: Playwright) -> Browser:
    try:
        return await playwright.chromium.launch()
    except PlaywrightError as e:
        if "Executable doesn't exist" not in str(e):
            raise
        fallback_executable = _find_chromium_executable()
        if not fallback_executable:
            raise PDFRenderError(
                "Playwright browser executable is missing, and no system Chrome/Edge "
                "installation was found. Install Playwright browsers or install Chrome/Edge."
            ) from e
        return await playwright.chromium.launch(executable_path=fallback_executable)


async def _render_page_to_pdf(
    page: Page,
    url: str,
    selector: str,
    pdf_format: str,
    pdf_margins: dict,
) -> bytes:
    # NOTE: do NOT use wait_until="networkidle" here. The Next.js dev server
    # (HMR/Turbopack + RSC streaming) keeps the network busy, so "idle" may
    # never arrive and goto silently hangs until timeout → 503 (issues
    # #799/#808), with the failure depending on environment/network noise.
    # Wait on the real readiness condition instead — document "load", the

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Run `playwright install chromium` (add `--with-deps` on Debian/Ubuntu for system libraries)
  2. Or install system Chrome/Edge so _find_chromium_executable() finds a fallback executable
  3. In Docker, add a build step: `RUN playwright install --with-deps chromium`
  4. Cache the Playwright browser directory in CI to avoid reinstalling each run

Example fix

// Dockerfile before
RUN pip install playwright
// after
RUN pip install playwright && playwright install --with-deps chromium
Defensive patterns

Strategy: fallback

Validate before calling

import shutil
from playwright.sync_api import sync_playwright

def browser_available() -> bool:
    try:
        with sync_playwright() as p:
            p.chromium.launch().close()
        return True
    except Exception:
        return bool(shutil.which("chrome") or shutil.which("chromium") or shutil.which("msedge"))

Try / catch

try:
    pdf = await render_resume_pdf(resume_id)
except PDFRenderError as e:
    if 'executable is missing' in str(e):
        log.critical("Playwright browsers not installed; run `playwright install chromium`")
        return HTMLFallbackResponse(resume_id)  # degrade to printable HTML
    raise

Prevention

When it happens

Trigger: PDF rendering requested (init_pdf_renderer or _run) while the Playwright Chromium bundle was never downloaded and no system chrome/chromium/msedge binary is on PATH or in standard install locations.

Common situations: Fresh deploy/Docker image that ran `pip install playwright` but skipped `playwright install chromium`; slim container images without system Chrome; CI runners without browser caching.

Related errors


AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28). Data as JSON: /api/errors/844f37e4b71a45f8. Report an issue: GitHub.