{"record":{"id":"cddf67907ff2f7f0","repo":"srbhr/Resume-Matcher","slug":"could-not-update-the-resume-draft","errorCode":null,"errorMessage":"Could not update the resume draft.","messagePattern":"Could not update the resume draft\\.","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"error","filePath":"apps/backend/app/routers/resume_wizard.py","lineNumber":60,"sourceCode":"            return ResumeWizardTurnResponse(state=apply_review(request.state))\n\n        # Cost guard: once the question cap is reached, stop making LLM calls for\n        # answer/skip turns and route the user to review instead of advancing.\n        if request.state.asked_count >= RESUME_WIZARD_MAX_QUESTIONS:\n            return ResumeWizardTurnResponse(state=apply_review(request.state))\n\n        if action == \"skip\":\n            state = await run_ai_turn(request.state, \"\", skip=True)\n            return ResumeWizardTurnResponse(state=state)\n\n        answer_text = request.answer.text if request.answer else \"\"\n        state = await run_ai_turn(request.state, answer_text, skip=False)\n        return ResumeWizardTurnResponse(state=state)\n    except HTTPException:\n        raise\n    except ValueError as e:\n        logger.error(\"Resume wizard turn validation failed: %s\", e)\n        raise HTTPException(status_code=422, detail=\"Could not update the resume draft.\")\n    except Exception as e:\n        logger.error(\"Resume wizard turn failed: %s\", e)\n        raise HTTPException(\n            status_code=500,\n            detail=\"Resume wizard failed. Please try again.\",\n        )\n\n\n@router.post(\"/finalize\", response_model=ResumeWizardFinalizeResponse)\nasync def finalize_resume_wizard(\n    request: ResumeWizardFinalizeRequest,\n) -> ResumeWizardFinalizeResponse:\n    \"\"\"Create the master resume from a validated wizard draft.\"\"\"\n    try:\n        current_master = await db.get_master_resume()\n        if current_master and current_master.get(\"processing_status\") == \"ready\":\n            raise HTTPException(\n                status_code=409,","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/resume_wizard.py#L42-L78","documentation":"A 422 raised by resume_wizard_turn when run_ai_turn raises ValueError, meaning the wizard state or answer text failed validation (e.g. invalid state transition, malformed answer for the current step). The underlying message is logged; clients get a generic draft-update failure.","triggerScenarios":"Answering a wizard step with text that doesn't parse into the expected field type; posting a turn against a stale/invalid wizard state; calling the turn endpoint out of order (skipping steps the state machine requires).","commonSituations":"Client replays an old answer after the wizard state advanced; frontend sends free text where a structured value (date, number) is expected; wizard state was reset server-side while the client kept its local copy.","solutions":["Inspect server logs for 'Resume wizard turn validation failed' to see the exact ValueError","Re-fetch the current wizard state and resubmit an answer valid for that step","Validate the answer format client-side before sending (dates, enums, required fields)","If the state is unrecoverable, restart the wizard session"],"exampleFix":"// before\nawait api.post('/resume-wizard/turn', { state, answer: rawInput });\n// after\nconst parsed = stepSchema.safeParse(rawInput);\nif (!parsed.success) showStepError(parsed.error);\nelse await api.post('/resume-wizard/turn', { state, answer: parsed.data });","handlingStrategy":"validation","validationCode":"function validateWizardAnswer(step, answer) {\n  if (answer == null || String(answer).trim() === '') throw new ValidationError('Answer is required');\n  if (step.expectedType === 'date' && isNaN(Date.parse(answer))) throw new ValidationError('Invalid date');\n  if (step.expectedType === 'number' && isNaN(Number(answer))) throw new ValidationError('Expected a number');\n}","typeGuard":"function isWellFormedState(state) {\n  return state != null && typeof state === 'object' &&\n    typeof state.current_step === 'string' && state.resume_data != null;\n}","tryCatchPattern":"try {\n  await api.post('/resume-wizard/turn', { state, answer });\n} catch (e) {\n  if (e.response?.status === 422) {\n    const fresh = await api.get('/resume-wizard/state'); // resync and let user re-answer\n    showStepRetry(fresh);\n  } else throw e;\n}","preventionTips":["Re-fetch wizard state before each turn instead of trusting a local copy","Validate answer format per step type before submitting","Prevent out-of-order step submissions in the UI","Surface the 422 as a 'please re-answer this step' prompt, not a crash"],"tags":["http","validation","wizard","fastapi"],"backgroundTag":"wizard-step-validation-failed","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}