srbhr/Resume-Matcher · error · Error

${text || Resume wizard finalize failed with status ${respon

Error message

${text || Resume wizard finalize failed with status ${response.status}}

What it means

finalizeResumeWizard in apps/frontend/lib/api/resume-wizard.ts throws this Error when the POST to `/resume-wizard/finalize` returns a non-OK response. It reads the raw response text as the error message (falling back to a status-embedded string), meaning the backend refused to finalize the wizard state into a finished resume.

Source

Thrown at apps/frontend/lib/api/resume-wizard.ts:121

export async function postResumeWizardTurn(
  payload: ResumeWizardTurnRequest
): Promise<ResumeWizardTurnResponse> {
  const response = await apiPost('/resume-wizard/turn', payload);
  if (!response.ok) {
    const text = await response.text().catch(() => '');
    throw new Error(text || `Resume wizard turn failed with status ${response.status}`);
  }
  return response.json();
}

export async function finalizeResumeWizard(
  state: ResumeWizardState
): Promise<ResumeWizardFinalizeResponse> {
  const response = await apiPost('/resume-wizard/finalize', { state });
  if (!response.ok) {
    const text = await response.text().catch(() => '');
    throw new Error(text || `Resume wizard finalize failed with status ${response.status}`);
  }
  return response.json();
}

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Inspect response.status and the raw text; treat HTML-looking bodies as gateway errors and check the proxy.
  2. For 422, validate the ResumeWizardState (all required sections completed) before finalizing.
  3. For 401, re-authenticate, restore the state, and retry finalize.
  4. For 5xx/429, retry with backoff and verify backend AI/timeout configuration.
  5. Persist wizard state locally so a failed finalize can be retried without losing progress.

Example fix

// before
const response = await apiPost('/resume-wizard/finalize', { state });
if (!response.ok) {
  const text = await response.text().catch(() => '');
  throw new Error(text || `Resume wizard finalize failed with status ${response.status}`);
}
// after
const response = await apiPost('/resume-wizard/finalize', { state });
if (!response.ok) {
  if (response.status === 401) throw new Error('Session expired. Please sign in and finalize again.');
  const text = await response.text().catch(() => '');
  throw new Error(text || `Resume wizard finalize failed with status ${response.status}`);
}
Defensive patterns

Strategy: validation

Validate before calling

function canFinalize(state: ResumeWizardState): boolean {
  return Boolean(state && Array.isArray(state.messages) && state.messages.length > 0);
}
if (!canFinalize(state)) throw new Error('Wizard state is incomplete — finalize requires a completed conversation.');

Type guard

function isFinalizableState(s: unknown): s is ResumeWizardState {
  return typeof s === 'object' && s !== null && 'messages' in s &&
    Array.isArray((s as ResumeWizardState).messages);
}

Try / catch

try {
  const result = await finalizeResumeWizard(state);
} catch (e) {
  const msg = e instanceof Error ? e.message : '';
  if (msg.includes('status 401')) { await reauth(); return finalizeResumeWizard(state); }
  showError('Finalizing your resume failed. Your progress is saved — please retry.');
}

Prevention

When it happens

Trigger: apiPost('/resume-wizard/finalize', { state }) yields response.ok === false: 401 unauthenticated, 404 resume/state id not found, 422 state object incomplete or from an incompatible wizard version, 429/500/504 from the AI finalization step.

Common situations: User reaches the final step after a long session and the cookie expired (401); the state was persisted before a schema migration and finalize now rejects it (422); final document generation exceeds a gateway timeout (504); backend storage failure while creating the resume (500).

Related errors


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