{"record":{"id":"8d1674d87115cc3d","repo":"srbhr/Resume-Matcher","slug":"failed-to-update-resume-status-res-status","errorCode":null,"errorMessage":"Failed to update resume (status ${res.status}): ${text}","messagePattern":"Failed to update resume \\(status (.+?)\\): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/frontend/lib/api/resume.ts","lineNumber":220,"sourceCode":"}\n\nexport async function fetchResumeList(includeMaster = false): Promise<ResumeListItem[]> {\n  const res = await apiFetch(`/resumes/list?include_master=${includeMaster ? 'true' : 'false'}`);\n  if (!res.ok) {\n    throw new Error(`Failed to load resumes list (status ${res.status}).`);\n  }\n  const payload = (await res.json()) as { data: ResumeListItem[] };\n  return payload.data;\n}\n\nexport async function updateResume(\n  resumeId: string,\n  resumeData: ProcessedResume\n): Promise<ResumeResponse['data']> {\n  const res = await apiPatch(`/resumes/${encodeURIComponent(resumeId)}`, resumeData);\n  if (!res.ok) {\n    const text = await res.text().catch(() => '');\n    throw new Error(`Failed to update resume (status ${res.status}): ${text}`);\n  }\n  const payload = (await res.json()) as ResumeResponse;\n  return payload.data;\n}\n\nexport function getResumePdfUrl(\n  resumeId: string,\n  settings?: TemplateSettings,\n  locale?: Locale\n): string {\n  const normalizedId = normalizeResumeId(resumeId);\n  const params = new URLSearchParams();\n\n  if (settings) {\n    params.set('template', settings.template);\n    params.set('pageSize', settings.pageSize);\n    params.set('marginTop', String(settings.margins.top));\n    params.set('marginBottom', String(settings.margins.bottom));","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/frontend/lib/api/resume.ts#L202-L238","documentation":"updateResume saves edited resume data (ProcessedResume) via apiPatch to /resumes/{id}. On a non-OK response it reads the response body as text and throws this Error including both the status and the server's error message, making it the most diagnostic of the resume read/write errors. It means the backend rejected the resume update.","triggerScenarios":"apiPatch(`/resumes/${encodeURIComponent(resumeId)}`, resumeData) returns non-2xx: 422/400 from a ProcessedResume payload failing backend schema validation, 404 for an unknown resumeId, 401/403 for auth issues, or 409/500 from concurrent-edit or persistence failures.","commonSituations":"Builder 'save' (runSave) submitting resume JSON whose structure no longer matches what the backend expects after an API schema change; saving a resume deleted in another tab; oversized payload or invalid field types (e.g. null where array expected) rejected with 422.","solutions":["Read the ${text} portion of the message — it contains the backend's validation/error detail; fix the offending fields in resumeData.","Verify the resumeId still exists (fetchResumeList) before saving; re-sync UI state if it was deleted elsewhere.","Confirm the ProcessedResume shape matches the current backend contract after any API version change.","In runSave, catch the error, surface the server message to the user, and preserve local edits so they are not lost."],"exampleFix":"// before\nawait updateResume(resumeId, resumeData);\n\n// after\ntry {\n  await updateResume(resumeId, resumeData);\n} catch (e) {\n  const msg = (e as Error).message;\n  console.error('Resume update rejected:', msg); // includes server body\n  notifyUser(`Save failed: ${msg}`);\n}","handlingStrategy":"validation","validationCode":"function isValidProcessedResume(r: ProcessedResume): boolean {\n  return typeof r === 'object' && r !== null && 'id' in r;\n}\nif (!isValidProcessedResume(resumeData)) throw new Error('Invalid resume payload before PATCH');","typeGuard":"function isProcessedResume(x: unknown): x is ProcessedResume {\n  return typeof x === 'object' && x !== null && 'id' in x;\n}","tryCatchPattern":"try {\n  await updateResume(resumeId, resumeData);\n} catch (e) {\n  const detail = (e as Error).message.split(':').slice(1).join(':').trim();\n  notifyUser(`Save failed: ${detail || 'unknown server error'}`);\n}","preventionTips":["Validate ProcessedResume against the backend schema (zod/JSON schema) before PATCHing.","Surface the server body text from the error message to users — it names the failing field.","Re-check the resume still exists before save to avoid 404s after concurrent deletes.","Regenerate/refresh typed API models whenever the backend contract changes."],"tags":["http-status","patch","api-client","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}