{"record":{"id":"913ef46aed7a1751","repo":"srbhr/Resume-Matcher","slug":"resume-not-found-resume-id","errorCode":null,"errorMessage":"Resume not found: {resume_id}","messagePattern":"Resume not found: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"apps/backend/app/database.py","lineNumber":318,"sourceCode":"    async def get_master_resume(self) -> dict[str, Any] | None:\n        \"\"\"Get the master resume if exists.\"\"\"\n        async with self._session() as session:\n            result = await session.execute(\n                select(Resume).where(Resume.is_master.is_(True))\n            )\n            row = result.scalars().first()\n            return self._resume_to_dict(row) if row else None\n\n    async def update_resume(self, resume_id: str, updates: dict[str, Any]) -> dict[str, Any]:\n        \"\"\"Update resume by ID.\n\n        Raises:\n            ValueError: If resume not found.\n        \"\"\"\n        async with self._session() as session:\n            row = await session.get(Resume, resume_id)\n            if row is None:\n                raise ValueError(f\"Resume not found: {resume_id}\")\n            for key, value in updates.items():\n                if hasattr(row, key):\n                    setattr(row, key, value)\n                else:\n                    logger.warning(\"Ignoring unknown resume field on update: %s\", key)\n            row.updated_at = _now()\n            await session.commit()\n            return self._resume_to_dict(row)\n\n    async def delete_resume(self, resume_id: str) -> bool:\n        \"\"\"Delete resume by ID.\"\"\"\n        async with self._session() as session:\n            row = await session.get(Resume, resume_id)\n            if row is None:\n                return False\n            await session.delete(row)\n            await session.commit()\n            return True","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/database.py#L300-L336","documentation":"update_resume in the backend database layer fetches a Resume row by primary key via session.get(Resume, resume_id) and raises ValueError when no row exists. It is the guard used by many write paths (upload, enhancements, cover letter updates, retries) to prevent silently updating a nonexistent record.","triggerScenarios":"Any caller of update_resume (apply_enhancements, upload_resume, update_resume_endpoint, retry_processing, update_cover_letter, apply_regenerated_items) passes a resume_id that has no matching row in the resumes table.","commonSituations":"Client holds a stale ID after the resume was deleted; ID passed with wrong type/format (e.g. string vs UUID mismatch in lookup); race between delete and update; user-supplied ID in an API call to a resource owned by another user.","solutions":["Verify the resume_id exists (SELECT or GET endpoint) before calling update_resume","Return 404 to the client when this ValueError propagates instead of a 500","Confirm the caller isn't passing a stale ID cached after deletion — refetch the resume list","Check that ID types match (UUID vs str) so session.get isn't silently missing the row"],"exampleFix":"// before\nawait update_resume(session, resume_id, updates);\n// after\nconst row = await get_resume(session, resume_id);\nif (!row) return notFoundResponse(resume_id);\nawait update_resume(session, resume_id, updates);","handlingStrategy":"validation","validationCode":"async def resume_exists(session, resume_id) -> bool:\n    return await session.get(Resume, resume_id) is not None\n\n# before updating:\nif not await resume_exists(session, resume_id):\n    raise HTTPException(status_code=404, detail=f\"Resume not found: {resume_id}\")","typeGuard":null,"tryCatchPattern":"try:\n    await update_resume(session, resume_id, updates)\nexcept ValueError as e:\n    if str(e).startswith(\"Resume not found\"):\n        raise HTTPException(status_code=404, detail=str(e)) from e\n    raise","preventionTips":["Always fetch-and-check the resume before mutating it","Map this ValueError to HTTP 404 in the API layer","Invalidate client-side caches when a resume is deleted","Normalize ID types (str vs UUID) at API boundaries"],"tags":["database","not-found","backend","async-sqlalchemy"],"backgroundTag":"record-not-found","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}