srbhr/Resume-Matcher · error · HTTPException (wraps PDFRenderError)
str(e)
Error message
str(e)
What it means
HTTP 503 raised by download_resume_pdf when the headless-browser PDF renderer throws PDFRenderError; the exception message (str(e)) becomes the response detail. Signals the PDF rendering service could not complete, typically a browser/Chromium launch or page-load failure.
Source
Thrown at apps/backend/app/routers/resumes.py:1663
f"&accentColor={accentColor}"
)
if lang:
params = f"{params}&lang={lang}"
url = f"{settings.frontend_base_url}/print/resumes/{resume_id}?{params}"
# Use the exact margins provided; compact mode only affects spacing.
pdf_margins = {
"top": marginTop,
"right": marginRight,
"bottom": marginBottom,
"left": marginLeft,
}
# Render PDF with margins applied to every page
try:
pdf_bytes = await render_resume_pdf(url, pageSize, margins=pdf_margins)
except PDFRenderError as e:
raise HTTPException(status_code=503, detail=str(e))
headers = {"Content-Disposition": f'attachment; filename="resume_{resume_id}.pdf"'}
return Response(content=pdf_bytes, media_type="application/pdf", headers=headers)
@router.delete("/{resume_id}")
async def delete_resume(resume_id: str) -> dict:
"""Delete a resume by ID."""
if not await db.delete_resume(resume_id):
raise HTTPException(status_code=404, detail="Resume not found")
return {"message": "Resume deleted successfully"}
@router.post("/{resume_id}/retry-processing", response_model=ResumeUploadResponse)
async def retry_processing(resume_id: str) -> ResumeUploadResponse:
"""Retry AI processing for a failed or stuck resume.
View on GitHub (pinned to 116f9cc3b0)
Solutions
- Read the 503 detail/str(e) and server logs to identify the renderer failure (browser missing, URL unreachable, timeout)
- Install the required browser binaries (e.g. `playwright install chromium`) in the deployment image
- Verify the print page URL is reachable from the renderer process and add required sandbox/no-sandbox flags
- Retry the download; if timeouts recur, increase the renderer timeout or resume size limits
Example fix
# Dockerfile before: no browser installed RUN pip install -r requirements.txt # after RUN pip install -r requirements.txt RUN playwright install --with-deps chromium
Defensive patterns
Strategy: retry
Try / catch
async function downloadPdfWithRetry(resumeId, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try { return await downloadResumePdf(resumeId); }
catch (e) {
if (e.status === 503 && i < attempts - 1) { await sleep(2000 * (i + 1)); continue; }
if (e.status === 503) throw new Error('PDF service unavailable: ' + e.detail);
throw e;
}
}
} Prevention
- Ensure Chromium/playwright binaries are installed in deployment images
- Set required sandbox flags (or --no-sandbox) in containers/CI
- Verify the print page URL is deployed and reachable from the renderer
- Add renderer timeouts and health checks; alert on 503s
When it happens
Trigger: render_resume_pdf fails because Chromium is not installed or crashed, the print URL is unreachable from the renderer, page load times out, or renderer resource limits (memory) are hit on large resumes.
Common situations: Missing playwright/puppeteer browser binaries in the container image, sandbox flags missing in restricted environments (Docker/CI), print page deployment mismatch so the renderer URL 404s, or cold-start timeouts on serverless.
Related errors
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/166a114f29cd4c40.
Report an issue: GitHub.