srbhr/Resume-Matcher · error · HTTPException
Could not extract text from the uploaded file. The document
Error message
Could not extract text from the uploaded file. The document may be image-based or scanned. Please upload a text-based PDF/DOCX with selectable text, or run OCR first.
What it means
upload_resume raises this HTTP 422 after document parsing succeeded but produced no extractable text. It specifically guards against image-based or scanned PDFs where markdown_content is empty or whitespace-only, since downstream analysis requires selectable text.
Source
Thrown at apps/backend/app/routers/resumes.py:667
detail=f"File too large. Maximum size: {MAX_FILE_SIZE // (1024 * 1024)}MB",
)
if len(content) == 0:
raise HTTPException(status_code=400, detail="Empty file")
# Convert to markdown
try:
markdown_content = await parse_document(content, file.filename or "resume.pdf")
except Exception as e:
logger.error(f"Document parsing failed: {e}")
raise HTTPException(
status_code=422,
detail="Failed to parse document. Please ensure it's a valid PDF or DOCX file.",
)
# Validate extracted text is not empty (image-based PDFs / scanned documents)
if not markdown_content or not markdown_content.strip():
raise HTTPException(
status_code=422,
detail=(
"Could not extract text from the uploaded file. The document may be "
"image-based or scanned. Please upload a text-based PDF/DOCX with "
"selectable text, or run OCR first."
),
)
# Store in database first with "processing" status (atomic master assignment)
# original_markdown is preserved permanently for date reference even after
# builder saves overwrite `content` with JSON.
resume = await db.create_resume_atomic_master(
content=markdown_content,
content_type="md",
filename=file.filename,
processed_data=None,
processing_status="processing",
original_markdown=markdown_content,View on GitHub (pinned to 116f9cc3b0)
Solutions
- Run OCR on the document (e.g. ocrmypdf input.pdf output.pdf) and re-upload the OCR'd file
- Re-export the resume from its source application as a text-based PDF (Save As PDF, not print-to-image)
- Upload a DOCX version instead, which almost always contains selectable text
- Verify locally that text extraction works before uploading (pdftotext file.pdf returns non-empty output)
Example fix
// before: raw scanned PDF from flatbed scanner
upload_resume(file=open('scan.pdf','rb')) # 422 image-based
// after
subprocess.run(['ocrmypdf','scan.pdf','scan-ocr.pdf'])
upload_resume(file=open('scan-ocr.pdf','rb')) Defensive patterns
Strategy: validation
Validate before calling
async function hasSelectableText(file: File): Promise<boolean> {
if (file.type === 'application/pdf') {
const buf = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument({data: buf}).promise;
for (let i = 1; i <= Math.min(pdf.numPages, 3); i++) {
const tc = await (await pdf.getPage(i)).getTextContent();
if (tc.items.some(it => it.str.trim())) return true;
}
return false;
}
return true; // DOCX is text-based
}
if (!await hasSelectableText(file)) alert('Run OCR before uploading'); Type guard
function isTextBased(doc: {extractedText?: string | null}): doc is {extractedText: string} {
return typeof doc.extractedText === 'string' && doc.extractedText.trim().length > 0;
} Try / catch
try {
await api.uploadResume(file);
} catch (e) {
if (e.response?.status === 422 && /image-based|OCR/.test(e.response.data?.detail ?? '')) {
showOcrInstructions(); // e.g. link to ocrmypdf / online OCR
} else throw e;
} Prevention
- Only upload text-based PDFs (created via Save As PDF, not scans or print-to-image)
- Pre-check selectable text locally (select text in the PDF viewer; pdftotext returns output)
- Run ocrmypdf on any scanned document before upload
- Prefer DOCX when the source document is editable
When it happens
Trigger: POSTing a resume upload (POST to the resumes upload endpoint) with a PDF or DOCX whose pages are raster images (scanned document, photographed page, screenshot-exported PDF), so the parser extracts an empty/whitespace-only markdown_content.
Common situations: Users scan paper resumes into PDFs; resume exported from design tools as flattened images; faxed or photographed documents; PDF with embedded fonts the extractor cannot decode; OCR preprocessing was skipped.
Related errors
- Failed to parse document. Please ensure it's a valid PDF or
- missing_placeholders
- Failed to download resume (status ${res.status}): ${text}
- Failed to download cover letter (status ${res.status}): ${te
- Playwright browser executable is missing, and no system Chro
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/55d5d8e48c4e4415.
Report an issue: GitHub.