{"record":{"id":"0f08f461cc4ada67","repo":"pbakaus/impeccable","slug":"status-failed-res-status-res-statustext","errorCode":null,"errorMessage":"Status failed: ${res.status} ${res.statusText}","messagePattern":"Status failed: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugin/skills/impeccable/scripts/live-poll.mjs","lineNumber":138,"sourceCode":"  if (!res.ok) {\n    const body = await res.json().catch(() => ({}));\n    const failureLines = Array.isArray(body.failures)\n      ? body.failures.map((f) => `  ${f.file}${f.line != null ? `:${f.line}` : ''} ${f.message}`).join('\\n')\n      : null;\n    const parts = [body.error || res.statusText, body.reason, body.hint, failureLines, body._instructions].filter(Boolean);\n    throw new Error(parts.join('\\n'));\n  }\n}\n\nexport async function fetchServerStatus(base, token) {\n  const res = await fetch(`${base}/status?token=${token}`);\n  if (res.status === 401) {\n    const err = new Error('Authentication failed. The server token may have changed.');\n    err.code = 'AUTH_FAILED';\n    throw err;\n  }\n  if (!res.ok) {\n    throw new Error(`Status failed: ${res.status} ${res.statusText}`);\n  }\n  return res.json();\n}\n\nexport function isEventPending(status, eventId) {\n  return (status.pendingEvents || []).some((entry) => entry.id === eventId);\n}\n\nexport async function waitForEventAck(base, token, eventId, {\n  pollIntervalMs = 400,\n  maxWaitMs = 600_000,\n} = {}) {\n  const deadline = Date.now() + maxWaitMs;\n  while (Date.now() < deadline) {\n    const status = await fetchServerStatus(base, token);\n    if (!isEventPending(status, eventId)) return true;\n    await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n  }","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/plugin/skills/impeccable/scripts/live-poll.mjs#L120-L156","documentation":"Thrown by fetchServerStatus() when GET /status?token=... returns a non-ok, non-401 status. 401 is mapped separately to an AUTH_FAILED error; everything else (500, 404, 503, etc.) becomes this generic message with the raw status code and status text. The status endpoint is polled to check pending events and ack state.","triggerScenarios":"Live server crashed and the port is now served by something else (404); internal server error (500) during status serialisation; the server restarted with in-memory state lost and returns 503; a proxy/firewall returns an unexpected status. Network errors (ECONNREFUSED) surface as fetch rejections, not this message.","commonSituations":"Server process died but the port wasn't freed; stale server.json pointing at a port a different process now owns; transient overload; version mismatch between poll client and server where the /status route changed.","solutions":["Restart the live server: stop it (`live-server.mjs stop` or kill the pid in server.json) and start fresh with `live.mjs`.","Confirm server.json (in .impeccable/live/) port matches the actually listening process; re-run setup if stale.","Check the server's stdout/log for the stack trace behind the 5xx.","If a 404, the route may have been renamed in an upgrade — align poll client and server versions."],"exampleFix":"// before\nconst status = await fetchServerStatus(base, token);\n\n// after\nlet status;\ntry {\n  status = await fetchServerStatus(base, token);\n} catch (err) {\n  if (/Status failed: 5\\d\\d/.test(err.message)) {\n    console.error('Server error, restarting live session');\n    // stop + restart live.mjs, then retry once\n  }\n  throw err;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function safeStatus(base, token, retries = 1) {\n  for (let attempt = 0; ; attempt++) {\n    try {\n      return await fetchServerStatus(base, token);\n    } catch (err) {\n      if (err.code === 'AUTH_FAILED') throw err;\n      if (attempt < retries && /Status failed: 5\\d\\d/.test(err.message)) {\n        await new Promise((r) => setTimeout(r, 500));\n        continue;\n      }\n      throw err;\n    }\n  }\n}","preventionTips":["Handle 401 (AUTH_FAILED) separately — restart the session, don't retry the same token.","Align poll-client and server versions so the /status route exists and returns the expected shape.","If 5xx persists, restart live.mjs rather than looping on retries."],"tags":["live-poll","network","http"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}