srbhr/Resume-Matcher · error · ValueError

Improved personalInfo is not a dict: {type(improved_info).__

Error message

Improved personalInfo is not a dict: {type(improved_info).__name__}

What it means

JSON-008 type guard on the improved side: improved_data.personalInfo must be a dict to allow field-by-field comparison with the original. If it is present but not a dict, the ValueError embeds the actual type name and the confirm endpoint surfaces HTTP 400. This prevents persisting a tailored resume whose identity block has the wrong structure.

Source

Thrown at apps/backend/app/routers/resumes.py:542

) -> None:
    if not original_data:
        logger.warning(
            "Skipping confirm payload validation; structured resume data unavailable."
        )
        return
    original_info = original_data.get("personalInfo")
    improved_info = improved_data.get("personalInfo")
    # JSON-008: Explicit null checks with clear error messages
    if original_info is None:
        raise ValueError("Original resume missing personalInfo")
    if improved_info is None:
        raise ValueError("Improved resume missing personalInfo")
    if not isinstance(original_info, dict):
        raise ValueError(
            f"Original personalInfo is not a dict: {type(original_info).__name__}"
        )
    if not isinstance(improved_info, dict):
        raise ValueError(
            f"Improved personalInfo is not a dict: {type(improved_info).__name__}"
        )
    fields = set(original_info.keys()) | set(improved_info.keys())
    mismatches = [
        field
        for field in sorted(fields)
        if _normalize_personal_info_value(original_info.get(field))
        != _normalize_personal_info_value(improved_info.get(field))
    ]
    if mismatches:
        raise ValueError(f"personalInfo fields changed: {', '.join(mismatches)}")


async def _generate_auxiliary_messages(
    improved_data: dict[str, Any],
    job_content: str,
    language: str,
    enable_cover_letter: bool,

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Validate the improved payload shape client-side before calling confirm (personalInfo must be an object)
  2. Re-run preview and use its improved data verbatim
  3. If caused by the pipeline, inspect generate_resume_diffs/apply_diffs output for personalInfo path corruption

Example fix

// before: LLM emitted a list
"personalInfo": ["Jane Doe", "jane@example.com"]
// after
"personalInfo": {"name": "Jane Doe", "email": "jane@example.com"}
Defensive patterns

Strategy: type-guard

Validate before calling

// client: validate the improved payload before confirm
function validPersonalInfo(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}
if (!validPersonalInfo(improvedData.personalInfo)) throw new TypeError('personalInfo must be an object');

Type guard

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

Try / catch

try {
  await api.post('/resumes/improve/confirm', body);
} catch (e) {
  if (e.response?.status === 400) {
    const preview = await api.post('/resumes/improve/preview', previewPayload);
    // retry using the canonical preview output
  }
}

Prevention

When it happens

Trigger: POST /resumes/improve/confirm where the improved payload's personalInfo is a non-dict (string, list, etc.) — typically a client-sent malformed confirm body, or an LLM/diff step emitting personalInfo as an array of strings.

Common situations: Hand-crafted confirm requests in scripts/tests; LLM JSON-mode output shape drift; automated tooling posting transformed data without schema validation.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28). Data as JSON: /api/errors/cc126d5d8730c2a0. Report an issue: GitHub.