pbakaus/impeccable · error · Error

Status failed: ${res.status} ${res.statusText}

Error message

Status failed: ${res.status} ${res.statusText}

What it means

Thrown by fetchServerStatus() in live-poll.mjs when GET {base}/status?token=... returns a non-OK status other than 401. A 401 is handled separately with an AUTH_FAILED error code; every other failure (5xx, 404, 403) collapses to this generic message carrying the numeric status and statusText. The function returns res.json() on success, so any non-JSON or error response aborts the status handshake.

Source

Thrown at skill/scripts/live-poll.mjs:138

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    const failureLines = Array.isArray(body.failures)
      ? body.failures.map((f) => `  ${f.file}${f.line != null ? `:${f.line}` : ''} ${f.message}`).join('\n')
      : null;
    const parts = [body.error || res.statusText, body.reason, body.hint, failureLines, body._instructions].filter(Boolean);
    throw new Error(parts.join('\n'));
  }
}

export async function fetchServerStatus(base, token) {
  const res = await fetch(`${base}/status?token=${token}`);
  if (res.status === 401) {
    const err = new Error('Authentication failed. The server token may have changed.');
    err.code = 'AUTH_FAILED';
    throw err;
  }
  if (!res.ok) {
    throw new Error(`Status failed: ${res.status} ${res.statusText}`);
  }
  return res.json();
}

export function isEventPending(status, eventId) {
  return (status.pendingEvents || []).some((entry) => entry.id === eventId);
}

export async function waitForEventAck(base, token, eventId, {
  pollIntervalMs = 400,
  maxWaitMs = 600_000,
} = {}) {
  const deadline = Date.now() + maxWaitMs;
  while (Date.now() < deadline) {
    const status = await fetchServerStatus(base, token);
    if (!isEventPending(status, eventId)) return true;
    await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
  }

View on GitHub (pinned to d14711ae3d)

Solutions

  1. Confirm the base URL and port point at the Impeccable Live server (not the app dev server or a proxy).
  2. Check the server process is alive and inspect its logs for the matching status code.
  3. If 401-style but reported as 403, verify the token matches the one the server booted with.
  4. Retry once the server is healthy; persistent 5xx indicates a server bug to file.
Defensive patterns

Strategy: retry

Validate before calling

// Cheap preflight before the status handshake.
async function isReachable(base) {
  try { const r = await fetch(base, { method: 'HEAD' }); return r.ok || r.status < 500; } catch { return false; }
}
if (!(await isReachable(base))) throw new Error('live server unreachable at ' + base);

Try / catch

try {
  const status = await fetchServerStatus(base, token);
} catch (err) {
  if (err.code === 'AUTH_FAILED') throw err; // re-raise auth, handled elsewhere
  // transient server error — back off and retry with jitter
  console.warn('status fetch failed:', err.message);
  throw err;
}

Prevention

When it happens

Trigger: fetchServerStatus(base, token) is invoked (by waitForEventAck, the live agent loop, or a manual health check) and the server responds with e.g. 500 Internal Server Error, 502 Bad Gateway, 404 (wrong base URL), or 403. A 401 would have thrown 'Authentication failed' with code AUTH_FAILED instead.

Common situations: Live server crashed or is restarting (5xx); base URL is wrong/proxied and hits a different service (404); reverse proxy or Cloudflare Pages Functions returned an error page; server version mismatch where /status route was renamed; port confusion pointing at a different dev server.

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/241e50e7b1bfe963. Report an issue: GitHub.