srbhr/Resume-Matcher · error · PDFRenderError
PDF renderer failed to initialize.
Error message
PDF renderer failed to initialize.
What it means
PDFRenderError raised in render_resume_pdf when the module-level lazy-initialized `_browser` is still None after the init path ran, meaning the renderer never successfully started. It guards the render call against using an uninitialized Playwright browser instance.
Source
Thrown at apps/backend/app/pdf.py:333
try:
await init_pdf_renderer()
except NotImplementedError:
async with _subprocess_lock:
_subprocess_supported = False
subprocess_supported = False
except PlaywrightError as e:
_raise_playwright_error(e, url)
if not subprocess_supported:
try:
return await _render_resume_pdf_in_thread(
url, selector, pdf_format, pdf_margins
)
except PlaywrightError as e:
_raise_playwright_error(e, url)
if _browser is None:
raise PDFRenderError("PDF renderer failed to initialize.")
try:
return await _render_with_browser(_browser, url, selector, pdf_format, pdf_margins)
except PlaywrightError as e:
_raise_playwright_error(e, url)
View on GitHub (pinned to 116f9cc3b0)
Solutions
- Check earlier server logs for the underlying Playwright launch failure (missing executable, launch timeout)
- Run `<python> -m playwright install chromium` in the deployment environment
- Restart the backend so lazy init retries on the next request
- Add retry/init-failure propagation around the browser initialization step
- Ensure only the app's event loop policy allows subprocesses (_loop_supports_subprocess) so init can run on Windows
Defensive patterns
Strategy: retry
Validate before calling
from app import pdf
def renderer_ready() -> bool:
return pdf._browser is not None Try / catch
try:
pdf_bytes = await render_resume_pdf(url, selector)
except PDFRenderError as e:
if str(e) == "PDF renderer failed to initialize.":
await asyncio.sleep(1)
pdf_bytes = await render_resume_pdf(url, selector) # retry re-runs lazy init
else:
raise Prevention
- Check deploy logs for the browser-install step succeeding before serving traffic
- Wrap lazy init with explicit error propagation instead of leaving _browser None
- Warm up the renderer at startup with a probe render
- Serialize init so concurrent first requests don't race the launch
- On Windows ensure the subprocess-friendly event loop policy is set
When it happens
Trigger: render_resume_pdf is called but `_browser` remains None because the lazy init (get/launch browser) failed or was skipped, and the failure path didn't already raise a more specific error.
Common situations: First PDF request arriving before/while browser initialization failed; Playwright runtime missing browsers in a fresh deploy; init exception swallowed in the init helper; concurrent requests racing an in-progress init that failed.
Related errors
- Playwright browser executable is missing, and no system Chro
- Playwright browser executable is missing or out of date. Com
- Cannot connect to frontend for PDF generation. Attempted URL
- PDF rendering failed. Please try again, or try a simpler res
- Failed to download resume (status ${res.status}): ${text}
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/50e32abcb8724a4b.
Report an issue: GitHub.