{"record":{"id":"15074ebd30aa65dc","repo":"srbhr/Resume-Matcher","slug":"original-personalinfo-is-not-a-dict-type-origina","errorCode":null,"errorMessage":"Original personalInfo is not a dict: {type(original_info).__name__}","messagePattern":"Original personalInfo is not a dict: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"apps/backend/app/routers/resumes.py","lineNumber":538,"sourceCode":"\ndef _validate_confirm_payload(\n    original_data: dict[str, Any] | None,\n    improved_data: dict[str, Any],\n) -> None:\n    if not original_data:\n        logger.warning(\n            \"Skipping confirm payload validation; structured resume data unavailable.\"\n        )\n        return\n    original_info = original_data.get(\"personalInfo\")\n    improved_info = improved_data.get(\"personalInfo\")\n    # JSON-008: Explicit null checks with clear error messages\n    if original_info is None:\n        raise ValueError(\"Original resume missing personalInfo\")\n    if improved_info is None:\n        raise ValueError(\"Improved resume missing personalInfo\")\n    if not isinstance(original_info, dict):\n        raise ValueError(\n            f\"Original personalInfo is not a dict: {type(original_info).__name__}\"\n        )\n    if not isinstance(improved_info, dict):\n        raise ValueError(\n            f\"Improved personalInfo is not a dict: {type(improved_info).__name__}\"\n        )\n    fields = set(original_info.keys()) | set(improved_info.keys())\n    mismatches = [\n        field\n        for field in sorted(fields)\n        if _normalize_personal_info_value(original_info.get(field))\n        != _normalize_personal_info_value(improved_info.get(field))\n    ]\n    if mismatches:\n        raise ValueError(f\"personalInfo fields changed: {', '.join(mismatches)}\")\n\n\nasync def _generate_auxiliary_messages(","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/resumes.py#L520-L556","documentation":"JSON-008 type guard: the original resume's personalInfo must be a dict/object for the field-level immutability comparison (set of keys unioned, values normalized and compared). If it exists but is not a dict (e.g. a string, list, or number from malformed stored data), this ValueError is raised with the actual Python type name embedded, and the endpoint returns HTTP 400.","triggerScenarios":"POST /resumes/improve/confirm where the stored processed_data.personalInfo is a non-dict value — caused by hand-edited DB rows, a buggy earlier parser writing personalInfo as a string, or a JSON upload where personalInfo was a list.","commonSituations":"Direct SQLite manipulation; older schema versions where personalInfo held a flat string; test fixtures with wrong shape.","solutions":["Fix the stored resume via PATCH /resumes/{id} so personalInfo is a JSON object","Re-upload/retry-processing the resume to regenerate well-typed processed_data","Fix the producer that wrote the wrong shape (parser or migration script)"],"exampleFix":"// before: malformed stored data\n\"personalInfo\": \"Jane Doe, jane@example.com\"\n// after\n\"personalInfo\": {\"name\": \"Jane Doe\", \"email\": \"jane@example.com\"}","handlingStrategy":"type-guard","validationCode":"# client: verify shape before confirming\nif not isinstance(original[\"processed_data\"].get(\"personalInfo\"), dict):\n    raise TypeError(\"original personalInfo must be an object\")","typeGuard":"def is_dict(v: object) -> bool:\n    return isinstance(v, dict)","tryCatchPattern":"try:\n    confirm(improved)\nexcept ValueError as e:\n    if 'personalInfo is not a dict' in str(e):\n        repair_personal_info_shape(resume_id)  # PATCH the stored data","preventionTips":["Treat processed_data.personalInfo as an object everywhere (no string encodings)","Validate JSON resume uploads against the ResumeData schema before storing","Run unit fixtures through the real schema so malformed shapes never reach the DB"],"tags":["validation","type-error","personal-info","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}