srbhr/Resume-Matcher · error · PDFRenderError
str(e) (message from PDFRenderError)
Error message
str(e) (message from PDFRenderError)
What it means
HTTP 503 raised when render_resume_pdf fails with PDFRenderError while snapshotting the cover-letter print page headlessly (e.g. Playwright/Puppeteer). The raw renderer message (str(e)) is passed through as the detail. 503 signals the rendering service is temporarily unavailable or the page failed to render.
Source
Thrown at apps/backend/app/routers/resumes.py:2055
cover_letter = resume.get("cover_letter")
if not cover_letter:
raise HTTPException(
status_code=404, detail="No cover letter found for this resume"
)
# Build print URL (same pattern as resume PDF)
url = f"{settings.frontend_base_url}/print/cover-letter/{resume_id}?pageSize={pageSize}"
if lang:
url = f"{url}&lang={lang}"
# Render PDF with cover letter selector
try:
pdf_bytes = await render_resume_pdf(
url, pageSize, selector=".cover-letter-print"
)
except PDFRenderError as e:
raise HTTPException(status_code=503, detail=str(e))
headers = {
"Content-Disposition": f'attachment; filename="cover_letter_{resume_id}.pdf"'
}
return Response(content=pdf_bytes, media_type="application/pdf", headers=headers)
View on GitHub (pinned to 116f9cc3b0)
Solutions
- Check the PDFRenderError message in the 503 response/logs — fix the specific renderer cause (timeout, navigation, selector).
- Verify settings.frontend_base_url is reachable from the backend container (curl the print URL).
- Ensure the print route /print/cover-letter exists in the deployed frontend and the .cover-letter-print selector is present.
- In Docker, install headless-browser system dependencies and confirm the browser binary launches.
- Retry — if the renderer was temporarily saturated, a retry with backoff often succeeds.
Example fix
// before
except PDFRenderError as e:
raise HTTPException(status_code=503, detail=str(e))
// after (retry transient render failures)
except PDFRenderError as e:
if e.is_transient:
pdf_bytes = await render_resume_pdf(url, pageSize, selector=".cover-letter-print")
else:
raise HTTPException(status_code=503, detail=str(e)) Defensive patterns
Strategy: retry
Validate before calling
const printUrl = `${frontendBaseUrl}/print/cover-letter/${resumeId}`;
const ok = await fetch(printUrl).then(r => r.ok).catch(() => false);
if (!ok) throw new SkipError('print page unreachable — renderer would fail'); Try / catch
try {
return await withBackoff(() => downloadCoverLetterPdf(resumeId), {retries: 2});
} catch (e) {
if (e.status === 503) {
showStatus('PDF renderer temporarily unavailable: ' + e.detail + '. Check frontend_base_url and try again.');
return null;
}
throw e;
} Prevention
- Verify settings.frontend_base_url is reachable from the backend before rendering (health-check the print route).
- Install headless-browser system dependencies in the deployment image.
- Confirm the .cover-letter-print selector exists in the deployed frontend print page.
- Set generous renderer timeouts for large documents and alert on PDFRenderError rates.
When it happens
Trigger: The headless browser fails to load {frontend_base_url}/print/cover-letter/{id} — frontend unreachable, page JS error, selector .cover-letter-print absent, navigation timeout, or browser process launch failure.
Common situations: frontend_base_url misconfigured (wrong host/port, http vs https); print route not deployed in the backend's target environment; browser sandbox missing dependencies in Docker (e.g. libnss3); cover-letter content causing client-side render crash; timeouts on large documents.
Related errors
- str(e)
- Request timed out. If you are running a local LLM, increase
- Failed to load prompt config (status ${res.status}).
- ${data.detail || Failed to update prompt config (status ${re
- Failed to load feature prompts (status ${res.status}).
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/783f3c7b98220487.
Report an issue: GitHub.