{"record":{"id":"5b57dddb38825df9","repo":"srbhr/Resume-Matcher","slug":"answer-is-required-for-answer-actions","errorCode":null,"errorMessage":"answer is required for answer actions","messagePattern":"answer is required for answer actions","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"apps/backend/app/schemas/resume_wizard.py","lineNumber":86,"sourceCode":"    history: list[ResumeWizardHistoryEntry] = Field(default_factory=list)\n    asked_count: int = 0\n    inferred_skills: list[str] = Field(default_factory=list)\n    is_complete: bool = False\n    progress: ResumeWizardProgress = Field(default_factory=ResumeWizardProgress)\n    warnings: list[str] = Field(default_factory=list)\n\n\nclass ResumeWizardTurnRequest(BaseModel):\n    \"\"\"Request for one wizard turn.\"\"\"\n\n    state: ResumeWizardState\n    action: ResumeWizardAction\n    answer: ResumeWizardAnswer | None = None\n\n    @model_validator(mode=\"after\")\n    def _validate_answer_present(self) -> \"ResumeWizardTurnRequest\":\n        if self.action == \"answer\" and self.answer is None:\n            raise ValueError(\"answer is required for answer actions\")\n        return self\n\n\nclass ResumeWizardTurnResponse(BaseModel):\n    \"\"\"Response for one wizard turn.\"\"\"\n\n    state: ResumeWizardState\n\n\nclass ResumeWizardFinalizeRequest(BaseModel):\n    \"\"\"Request to create the master resume from the wizard draft.\"\"\"\n\n    state: ResumeWizardState\n\n    @model_validator(mode=\"after\")\n    def _validate_ready_to_finalize(self) -> \"ResumeWizardFinalizeRequest\":\n        if not self.state.resume_data.personalInfo.name.strip():\n            raise ValueError(\"personalInfo.name is required\")","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/schemas/resume_wizard.py#L68-L104","documentation":"ResumeWizardTurnRequest's model validator _validate_answer_present requires the 'answer' field to be populated when action == 'answer'. Since answer defaults to None, sending an answer action without an answer payload raises this ValueError at validation time.","triggerScenarios":"POSTing a ResumeWizardTurnRequest with action=\"answer\" and answer omitted or explicitly null.","commonSituations":"Frontend wizard state machine advances to the answer turn but forgets to attach the collected answer; API consumers testing with minimal payloads; skip/answer action confusion.","solutions":["Include a valid ResumeWizardAnswer object when action is \"answer\"","If the user has no answer, use the appropriate action (e.g. \"skip\") instead","Validate on the client before submitting that the answer is present for answer actions","Return a 422 with this message so the client can recover"],"exampleFix":"// before\nResumeWizardTurnRequest(action=\"answer\")\n// after\nResumeWizardTurnRequest(action=\"answer\", answer=ResumeWizardAnswer(text=\"My answer\"))","handlingStrategy":"validation","validationCode":"def turn_request_ok(r: dict) -> bool:\n    return r.get(\"action\") != \"answer\" or r.get(\"answer\") is not None","typeGuard":"def has_answer(r: ResumeWizardTurnRequest) -> bool:\n    return r.answer is not None","tryCatchPattern":"try:\n    req = ResumeWizardTurnRequest.model_validate(body)\nexcept ValidationError as e:\n    raise HTTPException(422, \"answer is required for answer actions\") from e","preventionTips":["Keep answer collection and action selection in sync in the wizard UI","Default non-answer actions (skip/done) when no answer text exists","Add a client-side pre-submit check tying action to answer presence"],"tags":["pydantic","validation","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}