srbhr/Resume-Matcher · error · ValueError

Improved resume missing personalInfo

Error message

Improved resume missing personalInfo

What it means

The mirror check of the original-side null guard: the improved resume produced by the pipeline must carry a personalInfo object so it can be compared field-by-field against the original. If the improved data's personalInfo is None, the confirm endpoint raises this ValueError (surfaced as HTTP 400) rather than silently persisting a resume whose identity block was lost.

Source

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

        return None, None, f"calculation_error: {str(e)}"


def _validate_confirm_payload(
    original_data: dict[str, Any] | None,
    improved_data: dict[str, Any],
) -> 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)}")

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Re-run POST /resumes/improve/preview so the safety nets (_preserve_personal_info etc.) regenerate a valid personalInfo block
  2. Echo the preview's improved data verbatim in the confirm request; never hand-build it
  3. Check improver/diff code changes if this reproduces deterministically (field block-list may be excluding personalInfo path)

Example fix

// before: confirm request with improved data missing the identity block
{"resume_id": "...", "job_id": "...", "improved_data": {"summary": "..."}}
// after: improved_data includes unchanged personalInfo copied from the preview
{"resume_id": "...", "job_id": "...", "improved_data": {"personalInfo": {"name": "Jane Doe"}, "summary": "..."}}
Defensive patterns

Strategy: validation

Validate before calling

// client: echo the preview's improved data verbatim, never rebuild it
if (!payload.improved_data?.personalInfo) {
  throw new Error('confirm payload must include personalInfo from the preview');
}

Type guard

const hasPersonalInfo = (d: unknown): d is { personalInfo: Record<string, unknown> } =>
  typeof d === 'object' && d !== null && 'personalInfo' in d && typeof (d as any).personalInfo === 'object' && (d as any).personalInfo !== null;

Try / catch

try {
  await api.post('/resumes/improve/confirm', body);
} catch (e) {
  if (e.response?.status === 400) {
    // re-run preview and retry with its canonical improved_data
    const preview = await api.post('/resumes/improve/preview', previewPayload);
    await api.post('/resumes/improve/confirm', buildConfirm(preview.data));
  }
}

Prevention

When it happens

Trigger: POST /resumes/improve/confirm where the preview/pipeline output (improved_data from processed/improved payload) has personalInfo missing or null — usually because an LLM or diff-application step dropped the field, or a client tampered with the improved payload.

Common situations: LLM returning JSON that omits personalInfo; legacy full-output improve path producing schema drift; client constructing a confirm request body manually instead of echoing the preview result.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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