srbhr/Resume-Matcher · error · HTTPException

Invalid file type: {file.content_type}. Allowed: PDF, DOC, D

Error message

Invalid file type: {file.content_type}. Allowed: PDF, DOC, DOCX

What it means

upload_resume validates the multipart file's content_type against the ALLOWED_TYPES set (PDF, DOC, DOCX) before reading it. Any other MIME type — including generic octet-stream — is rejected with HTTP 400 and this detail string naming the accepted types.

Source

Thrown at apps/backend/app/routers/resumes.py:639

ALLOWED_TYPES = {
    "application/pdf",
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
}
MAX_FILE_SIZE = 4 * 1024 * 1024  # 4MB


@router.post("/upload", response_model=ResumeUploadResponse)
async def upload_resume(file: UploadFile = File(...)) -> ResumeUploadResponse:
    """Upload and process a resume file (PDF/DOCX).

    Converts the file to Markdown and stores it in the database.
    Optionally parses to structured JSON if LLM is configured.
    """
    # Validate file type
    if file.content_type not in ALLOWED_TYPES:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid file type: {file.content_type}. Allowed: PDF, DOC, DOCX",
        )

    # Read and validate size
    content = await file.read()
    if len(content) > MAX_FILE_SIZE:
        raise HTTPException(
            status_code=413,
            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")

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Re-upload a real PDF or DOCX; when scripting, set the type explicitly: curl -F 'file=@resume.pdf;type=application/pdf'
  2. Convert unsupported formats (ODT/RTF/Pages) to DOCX or PDF first
  3. If your file IS a PDF/DOCX but the client sends octet-stream, fix the client to send the correct Content-Type header

Example fix

// before: curl sends application/octet-stream for .docx
curl -F "file=@resume.docx" http://localhost:8000/api/v1/resumes/upload
// after: explicit MIME type
curl -F "file=@resume.docx;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document" http://localhost:8000/api/v1/resumes/upload
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
if (!ALLOWED.includes(file.type)) {
  throw new Error(`Unsupported type ${file.type}; convert to PDF or DOCX first`);
}

Type guard

const isUploadable = (f: File): boolean =>
  ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(f.type);

Try / catch

try {
  await api.postForm('/resumes/upload', form);
} catch (e) {
  if (e.response?.status === 400 && /Invalid file type/.test(e.response?.data?.detail ?? '')) {
    showToast('Please upload a PDF or DOCX file');
  }
}

Prevention

When it happens

Trigger: POST /api/v1/resumes/upload with a file whose browser-supplied Content-Type is not in ALLOWED_TYPES: e.g. application/octet-stream (common for .docx on Linux/curl), text/plain, image/png, or files uploaded via curl without an explicit -F 'file=@resume.pdf;type=application/pdf'.

Common situations: curl/API scripts omitting the MIME type (defaults to octet-stream); exotic office formats (.odt, .rtf, .pages, .key); scanned image uploads; browser MIME sniffing differences across OSes.

Related errors


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