{"record":{"id":"b971eeada98656e7","repo":"srbhr/Resume-Matcher","slug":"failed-to-delete-resume-status-res-status","errorCode":null,"errorMessage":"Failed to delete resume (status ${res.status}): ${text}","messagePattern":"Failed to delete resume \\(status (.+?)\\): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/frontend/lib/api/resume.ts","lineNumber":281,"sourceCode":"  resumeId: string,\n  settings?: TemplateSettings,\n  locale?: Locale\n): Promise<Blob> {\n  const url = getResumePdfUrl(resumeId, settings, locale);\n  const res = await apiFetch(url);\n  if (!res.ok) {\n    const text = await res.text().catch(() => '');\n    throw new Error(`Failed to download resume (status ${res.status}): ${text}`);\n  }\n  return await res.blob();\n}\n\n/** Deletes a resume by ID */\nexport async function deleteResume(resumeId: string): Promise<void> {\n  const res = await apiDelete(`/resumes/${encodeURIComponent(resumeId)}`);\n  if (!res.ok) {\n    const text = await res.text().catch(() => '');\n    throw new Error(`Failed to delete resume (status ${res.status}): ${text}`);\n  }\n}\n\n/** Updates the cover letter for a resume */\nexport async function updateCoverLetter(resumeId: string, content: string): Promise<void> {\n  const res = await apiPatch(`/resumes/${encodeURIComponent(resumeId)}/cover-letter`, { content });\n  if (!res.ok) {\n    const text = await res.text().catch(() => '');\n    throw new Error(`Failed to update cover letter (status ${res.status}): ${text}`);\n  }\n}\n\n/** Updates the outreach message for a resume */\nexport async function updateOutreachMessage(resumeId: string, content: string): Promise<void> {\n  const res = await apiPatch(`/resumes/${encodeURIComponent(resumeId)}/outreach-message`, {\n    content,\n  });\n  if (!res.ok) {","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/frontend/lib/api/resume.ts#L263-L299","documentation":"deleteResume removes a resume by ID via apiDelete to /resumes/{id} and throws this Error (with status and response body text) when the response is not OK. It means the server refused or failed to delete the resume record. Raised in confirmDeleteAndReupload and handleDeleteResume flows.","triggerScenarios":"apiDelete(`/resumes/${encodeURIComponent(resumeId)}`) returns non-2xx: unknown/expired resumeId (404), auth failure (401/403), backend refusing deletion of a master/in-use resume (409/400), or persistence error (500).","commonSituations":"Deleting a resume that another tab already removed (404); attempting to delete a master resume the backend protects; dev database reset leaving stale UI entries; session expiry after idling on the resume management page.","solutions":["Check status in the message: 404 -> refresh the resume list (item already gone, treat as success); 401/403 -> re-authenticate.","Inspect the body text for backend-specific refusals (e.g. cannot delete master resume) and adjust the UI to prevent such deletes.","After a failed delete, re-fetch fetchResumeList to re-sync UI state with the server.","Catch the error in handleDeleteResume/confirmDeleteAndReupload and show the server's reason to the user instead of an unhandled rejection."],"exampleFix":"// before\nawait deleteResume(resumeId);\nsetResumes(resumes.filter((r) => r.id !== resumeId));\n\n// after\ntry {\n  await deleteResume(resumeId);\n} catch (e) {\n  console.error('Delete failed:', (e as Error).message);\n  notifyUser(`Delete failed: ${(e as Error).message}`);\n  return;\n}\nsetResumes(resumes.filter((r) => r.id !== resumeId));","handlingStrategy":"try-catch","validationCode":"const list = await fetchResumeList(false);\nif (!list.some((r) => r.id === resumeId)) {\n  console.warn('Resume already gone; skipping delete');\n  return;\n}","typeGuard":"function isDeletableResume(r: ResumeListItem): boolean {\n  return typeof r?.id === 'string' && r.id.length > 0;\n}","tryCatchPattern":"try {\n  await deleteResume(resumeId);\n} catch (e) {\n  if ((e as Error).message.includes('status 404')) {\n    setResumes((rs) => rs.filter((r) => r.id !== resumeId)); // already deleted\n    return;\n  }\n  notifyUser(`Delete failed: ${(e as Error).message}`);\n}","preventionTips":["Treat 404 on delete as success and reconcile the UI list instead of erroring.","Disable delete actions for master/protected resumes the backend refuses to remove.","Re-fetch the resume list after any delete attempt to stay in sync with the server.","Centralize 401 handling so idle users re-authenticate before destructive operations."],"tags":["http-status","delete","api-client","resume"],"backgroundTag":"http-error-response","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}