srbhr/Resume-Matcher · error · Error

${fallback} (status ${res.status}).

Error message

${fallback} (status ${res.status}).

What it means

asJson is the shared response-unwrapping helper for the tracker API module; when a response is not ok it throws this Error using either the backend's error detail (extractDetail) or the supplied fallback string plus the HTTP status. Every tracker call (list, create, get, update, bulk update, bulk delete) funnels through it, so any tracker API failure surfaces here.

Source

Thrown at apps/frontend/lib/api/tracker.ts:97

      .filter((m): m is string => Boolean(m));
    if (messages.length > 0) return messages.join('; ');
  }
  // A dict detail (e.g. HTTPException(detail={...})) — stringify so it reads as
  // something rather than "[object Object]".
  if (detail && typeof detail === 'object' && !Array.isArray(detail)) {
    try {
      return JSON.stringify(detail);
    } catch {
      return null;
    }
  }
  return null;
}

async function asJson<T>(res: Response, fallback: string): Promise<T> {
  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw new Error(extractDetail(data) || `${fallback} (status ${res.status}).`);
  }
  return res.json() as Promise<T>;
}

// List all applications grouped by status column.
export async function listApplications(): Promise<ApplicationListResponse> {
  const res = await apiFetch('/applications', { credentials: 'include' });
  return asJson<ApplicationListResponse>(res, 'Failed to load applications');
}

// Manually add a card from a pasted job description.
export async function createApplication(payload: ManualApplicationCreate): Promise<Application> {
  const res = await apiPost('/applications', payload);
  return asJson<Application>(res, 'Failed to create application');
}

// Fetch a card with its embedded JD + applied resume (for the modal).
export async function getApplicationDetail(id: string): Promise<ApplicationDetail> {

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Read the fallback text and status to identify which tracker call failed and why
  2. Ensure the backend API is running and its base URL/proxy is configured correctly
  3. Re-authenticate for 401 responses
  4. Validate the request payload (application status values, ids) for 400 errors
  5. Check for backend detail fields in responses so extractDetail returns a specific reason instead of the fallback

Example fix

// before
const list = await listApplications();
// after
try {
  const list = await listApplications();
} catch (e) {
  showBanner(`Applications unavailable: ${e.message}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate payloads before any tracker mutation that flows through asJson
function validateApplicationInput(input: { company: string; status: string }): string | null {
  if (!input.company.trim()) return 'Company is required';
  const allowed = ['wishlist', 'applied', 'interview', 'offer', 'rejected'];
  if (!allowed.includes(input.status)) return `Invalid status: ${input.status}`;
  return null;
}

Type guard

function isTrackerApiError(e: unknown): e is Error & { trackerCall?: string } {
  return e instanceof Error && e.message.includes('(status');
}

Try / catch

try {
  const data = await listApplications();
  render(data);
} catch (e) {
  if (e instanceof Error && /status 401/.test(e.message)) {
    redirectToLogin();
  } else if (e instanceof Error && /status 5\d\d/.test(e.message)) {
    showError('Tracker service temporarily unavailable. Retrying...');
  } else {
    showError(e instanceof Error ? e.message : 'Tracker request failed.');
  }
}

Prevention

When it happens

Trigger: Any non-2xx tracker response where the body has no parseable 'detail' field: 401 expired session, 404 application not found, 400 invalid payload on create/update, 500 server error, or network-level failure rendered as an error Response.

Common situations: Seen when the fallback text like 'Failed to list applications' appears with a status code: backend down during local dev, tracker API route changed/moved, malformed create/update payload, or auth cookie missing in a fresh browser session.

Related errors


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