jackwener/OpenCLI · warning
[opencli] daemon ping failed: HTTP ${res.status}
Error message
[opencli] daemon ping failed: HTTP ${res.status} What it means
A console warning from the extension's connectAttempt when the HTTP pre-flight ping to the daemon (DAEMON_PING_URL) returns a non-ok status. The extension treats this as 'daemon reachable but not answering correctly' and schedules a reconnect instead of opening the WebSocket, preventing a permanently wedged connect loop (e.g. after the daemon answers 431).
Source
Thrown at extension/src/background.ts:149
connectInFlight = attempt.finally(() => {
connectInFlight = null;
});
return connectInFlight;
}
async function connectAttempt(): Promise<void> {
if (isDaemonSocketActive()) return;
try {
// omit credentials so the browser doesn't attach the localhost cookie jar —
// a large jar can push the request past Node's default header limit and make
// the daemon answer 431, silently wedging the connect loop forever.
const res = await fetch(DAEMON_PING_URL, {
signal: AbortSignal.timeout(1000),
credentials: 'omit',
});
if (!res.ok) {
console.warn(`[opencli] daemon ping failed: HTTP ${res.status}`);
scheduleReconnect();
return; // unexpected response — not our daemon, but keep polling.
}
// Daemon is reachable — proceed straight to the WebSocket below.
reconnectAttempts = 0;
} catch {
// Daemon not running is the expected idle state — keep the probe silent to
// avoid per-poll service-worker noise (see connect() docstring). The 431
// wedge this fixes is surfaced in the !res.ok branch above.
scheduleReconnect();
return; // daemon not running — keep polling until the next daemon spawn.
}
if (isDaemonSocketActive()) return;
let thisWs: WebSocket;
try {
const contextId = await getCurrentContextId();
if (isDaemonSocketActive()) return;View on GitHub (pinned to 49907e53dc)
Solutions
- Restart the opencli daemon so it clears header/connection state
- Check what else is bound to the daemon port and kill the conflicting process
- Clear browser extension state / reload the extension to reset reconnect polling
- Bypass any proxy for localhost connections
Defensive patterns
Strategy: retry
Validate before calling
const res = await fetch(DAEMON_PING_URL, { signal: AbortSignal.timeout(1000) }).catch(() => null);
if (!res || !res.ok) await restartDaemon(); Try / catch
try { await connectDaemon(); } catch (e) { scheduleReconnect(); } Prevention
- Restart the daemon periodically or on suspicious 4xx responses
- Monitor the daemon port for conflicts
- Exclude localhost from proxies
- Reload the extension if reconnect polling wedges
When it happens
Trigger: The daemon HTTP endpoint returns 4xx/5xx (notably 431 Request Header Fields Too Large) during the 1-second-timeout fetch; a proxy or another process is listening on the daemon port and replies with an error status.
Common situations: Daemon accumulated too many/large headers (431); port collision with another local server; daemon restarting mid-poll; corporate proxy intercepting localhost traffic.
Related errors
- Detached HEAD — checkout a branch first
- autohome ${contextHint} network error: ${err?.message || err
- daemon-not-running
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/b56bb2975e3419e5.
Report an issue: GitHub.