srbhr/Resume-Matcher · error · HTTPException

A master resume already exists. Delete it before creating a

Error message

A master resume already exists. Delete it before creating a new one.

What it means

A 409 raised at the start of finalize_resume_wizard when db.get_master_resume() returns an existing resume already marked processing_status 'ready'. Only one master resume may exist; finalize is refused until it is deleted.

Source

Thrown at apps/backend/app/routers/resume_wizard.py:77

        logger.error("Resume wizard turn validation failed: %s", e)
        raise HTTPException(status_code=422, detail="Could not update the resume draft.")
    except Exception as e:
        logger.error("Resume wizard turn failed: %s", e)
        raise HTTPException(
            status_code=500,
            detail="Resume wizard failed. Please try again.",
        )


@router.post("/finalize", response_model=ResumeWizardFinalizeResponse)
async def finalize_resume_wizard(
    request: ResumeWizardFinalizeRequest,
) -> ResumeWizardFinalizeResponse:
    """Create the master resume from a validated wizard draft."""
    try:
        current_master = await db.get_master_resume()
        if current_master and current_master.get("processing_status") == "ready":
            raise HTTPException(
                status_code=409,
                detail="A master resume already exists. Delete it before creating a new one.",
            )

        normalized = normalize_resume_data(
            request.state.resume_data.model_dump(mode="json")
        )
        data = ResumeData.model_validate(normalized).model_dump(mode="json")
        content = json.dumps(data, ensure_ascii=False, sort_keys=True)
        name = data.get("personalInfo", {}).get("name", "").strip() or "Resume"
        title = f"{name} Master Resume"
        # Set the title in the atomic create so a separate update can't fail and
        # leave a committed-but-untitled master behind (which would 409 on retry).
        resume = await db.create_resume_atomic_master(
            content=content,
            content_type="json",
            filename=f"AI Resume Wizard - {name}.json",
            processed_data=data,

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Delete the existing master resume via the resume deletion endpoint, then re-run finalize
  2. Fetch the master resume first and skip the wizard if one already exists (redirect user to it)
  3. For tests/dev, clear the master resume in setup/teardown before finalizing
  4. Serialize finalize calls in the client so only one runs at a time

Example fix

// before
await api.post('/resume-wizard/finalize', { state });
// after
const master = await api.get('/resumes/master');
if (master?.processing_status === 'ready') {
  showToast('Master resume already exists');
} else {
  await api.post('/resume-wizard/finalize', { state });
}
Defensive patterns

Strategy: validation

Validate before calling

async function canFinalizeWizard(state) {
  const master = await api.get('/resumes/master').catch(e => e.response?.status === 404 ? null : Promise.reject(e));
  if (master && master.processing_status === 'ready') {
    throw new ConflictError('Master resume already exists — delete it or reuse it');
  }
  return true;
}

Type guard

function hasReadyMaster(r) {
  return r != null && r.processing_status === 'ready';
}

Try / catch

try {
  await api.post('/resume-wizard/finalize', { state });
} catch (e) {
  if (e.response?.status === 409) {
    navigate('/resumes/master'); // existing master wins
  } else throw e;
}

Prevention

When it happens

Trigger: Calling POST /resume-wizard/finalize when a ready master resume already exists; concurrent finalize calls after one succeeded; environment seeded with a master resume from a previous session.

Common situations: User finishes the wizard a second time without deleting the first master resume; two browser tabs finalize simultaneously; test/dev database reused across runs without cleanup.

Related errors


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