{"record":{"id":"1bd05dde94fd1895","repo":"srbhr/Resume-Matcher","slug":"resume-not-found-1bd05d","errorCode":null,"errorMessage":"Resume not found","messagePattern":"Resume not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"apps/backend/app/routers/resumes.py","lineNumber":731,"sourceCode":"        request_id=str(uuid4()),\n        resume_id=resume[\"resume_id\"],\n        processing_status=resume[\"processing_status\"],\n        is_master=resume.get(\"is_master\", False),\n    )\n\n\n@router.get(\"\", response_model=ResumeFetchResponse)\nasync def get_resume(resume_id: str = Query(...)) -> ResumeFetchResponse:\n    \"\"\"Fetch resume details by ID.\n\n    Returns both raw markdown and structured data (if available),\n    plus cover letter and outreach message if they exist.\n    Applies lazy migration for section metadata if needed.\n    \"\"\"\n    resume = await db.get_resume(resume_id)\n\n    if not resume:\n        raise HTTPException(status_code=404, detail=\"Resume not found\")\n\n    # Get processing status (default to \"pending\" for old records)\n    processing_status = resume.get(\"processing_status\", \"pending\")\n\n    # Build response\n    raw_resume = RawResume(\n        id=None,  # TinyDB doesn't have numeric IDs like SQL\n        content=resume[\"content\"],\n        content_type=resume[\"content_type\"],\n        created_at=resume[\"created_at\"],\n        processing_status=processing_status,\n    )\n\n    # Get processed data if available (no more on-demand parsing)\n    processed_data = resume.get(\"processed_data\")\n\n    # Apply lazy migration - add section metadata to old resumes\n    if processed_data:","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/resumes.py#L713-L749","documentation":"get_resume raises HTTP 404 when db.get_resume(resume_id) returns no document. This is the shared internal loader reused by get_application_detail, analyze_resume, generate_enhancements, apply_enhancements, regenerate_items and apply_regenerated_items, so a stale ID fails on every dependent endpoint.","triggerScenarios":"GET /resumes/{id} (or any caller passing a resume_id) where the ID does not exist in the database, was deleted, or the caller passes a truncated/mistyped ID (e.g. React Router param misconfiguration).","commonSituations":"Frontend uses a locally-generated UUID instead of the server-assigned ID; resume deleted in another tab; database was reset/reseeded while the client kept old IDs; wrong DB (dev vs prod) backing the backend.","solutions":["Confirm the resume_id in the request matches an existing record (list resumes via GET /resumes and compare)","Re-create the resume if the database was reset, and refresh the client's stored ID","Check that the frontend route parameter (e.g. useParams().id) is actually the resume ID, not an application or job ID","Verify the backend is pointed at the intended database (MONGODB_URI / env selection)"],"exampleFix":"// before\nfetch(`/api/resumes/${localStorage.id}`) // stale id from previous DB\n// after: fetch fresh list first and use a valid id\nconst list = await fetch('/api/resumes').then(r => r.json());\nfetch(`/api/resumes/${list.resumes[0].id}`)","handlingStrategy":"try-catch","validationCode":"async function resumeExists(id: string): Promise<boolean> {\n  const res = await fetch(`/api/resumes/${id}`);\n  return res.ok;\n}\nif (!(await resumeExists(resumeId))) await refreshResumeList();","typeGuard":"function isResumeRef(r: unknown): r is {resume_id: string} & Record<string, unknown> {\n  return typeof r === 'object' && r !== null &&\n    typeof (r as any).resume_id === 'string' && (r as any).resume_id.length > 0;\n}","tryCatchPattern":"try {\n  const resume = await api.getResume(id);\n} catch (e) {\n  if (e.response?.status === 404) {\n    invalidate(id); // drop stale ID, redirect to resume list / re-upload\n  } else throw e;\n}","preventionTips":["Always obtain resume_id from a server response (upload/list), never generate it client-side","Refresh or invalidate cached resume IDs after any delete or DB reseed","Check route params map to the right entity (resume vs application vs job ID)","Pin dev/prod to explicit DB env vars to avoid querying the wrong database"],"tags":["http-404","resource-not-found","database","stale-id"],"backgroundTag":"resource-not-found-404","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}