pbakaus/impeccable · error · Error
Status failed
Error message
Status failed: ${res.status} ${res.statusText} What it means
fetchServerStatus(base, token) in skill/scripts/live-poll.mjs issues GET ${base}/status?token=${token} against the Impeccable live server. A 401 is mapped first to AUTH_FAILED ('The server token may have changed.'), so this throw means the server answered HTTP but with a different non-OK status — 404, 500, 502, 504, etc. — and the message embeds the numeric status plus statusText for diagnosis.
Solutions
- Confirm the live server is running and read the port it prints; rebuild base from it
- Reproduce directly: curl "${base}/status?token=${token}" and inspect the status code and body
- Check the live-server console for a stack trace when the status is 5xx
- Remove any reverse proxy from the URL or fix its timeouts if it fronts the live server
- If the status flips to 401/AUTH_FAILED, the server token changed — re-read the current token instead of retrying the old one
Defensive patterns
Strategy: retry
Validate before calling
async function serverReachable(base, token) {
try {
const res = await fetch(`${base}/status?token=${token}`);
if (res.status === 401) return { ok: false, reason: 'AUTH_FAILED' };
return { ok: res.ok, reason: res.ok ? null : `HTTP ${res.status}` };
} catch (err) {
return { ok: false, reason: err.cause?.code || err.message }; // ECONNREFUSED etc.
}
}
const probe = await serverReachable(base, token);
if (!probe.ok) throw new Error(`live server not ready: ${probe.reason}`); Try / catch
for (let attempt = 1; attempt <= 3; attempt++) {
try {
status = await fetchServerStatus(base, token);
break;
} catch (err) {
if (err?.code === 'AUTH_FAILED') throw err; // token problem: retrying cannot help
const transient = /^Status failed: 5/.test(err?.message || '');
if (!transient || attempt === 3) throw err;
await backoff(attempt);
}
} Prevention
- Derive base from the port the live server prints at boot; never hardcode a stale one
- Distinguish 401/AUTH_FAILED (re-read the token) from 5xx (check server logs) before any retry
- Keep reverse proxies off the localhost live-server path or raise their timeouts
When it happens
Trigger: base points at the wrong port or includes a wrong path so an intermediary 404s; the live server hit an internal error (500) while handling /status; a reverse proxy/gateway in front of the server returns 502/504; a stale base from a previous server instance whose port now hosts a different service.
Common situations: The live server was restarted on a new port while the polling script kept the old base; another dev server (Vite/Astro) now occupies the port; corporate proxies or SSL-terminating fronts intercepting localhost requests.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Poll failed
- Could not check for updates
- Could not fetch command list from impeccable.style. Check…
- Live server not running. Start one with
- Live server not running. Start one with
AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18).
Data as JSON: /api/errors/241e50e7b1bfe963.
Report an issue: GitHub.
Appendix: 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 f88b2837a7)