thedotmack/claude-mem · warning
Worker API ${method} ${url} returned ${response.status}; ski
Error message
Worker API ${method} ${url} returned ${response.status}; skipping hook API call What it means
A hook's HTTP call to the worker (workerHttpRequest) got a non-ok response. For 429 or >=500 the hook logs this warning with the first 200 chars of the body, resets the worker failure counter, and returns a branded soft-fallback {continue: true, reason: 'worker_api_<status>'} so the hook completes without worker data rather than failing the Claude event. Other 4xx statuses are parsed as the endpoint's normal JSON error payload instead.
Source
Thrown at src/shared/worker-utils.ts:879
if (options.timeoutMs !== undefined) {
init.timeoutMs = options.timeoutMs;
}
let response: Response;
try {
response = await workerHttpRequest(url, init);
} catch (error) {
if (!boundedStartup) throw error;
logger.debug('SYSTEM', 'Worker unavailable for best-effort hook call', {
error: error instanceof Error ? error.message : String(error),
});
return { continue: true, reason: 'worker_unreachable', [WORKER_FALLBACK_BRAND]: true };
}
if (!response.ok) {
const text = await response.text().catch(() => '');
resetWorkerFailureCounter();
if (response.status === 429 || response.status >= 500) {
logger.warn('SYSTEM', `Worker API ${method} ${url} returned ${response.status}; skipping hook API call`, {
body: text.substring(0, 200),
});
return {
continue: true,
reason: `worker_api_${response.status}`,
[WORKER_FALLBACK_BRAND]: true,
};
}
let parsed: unknown = text;
try { parsed = JSON.parse(text); } catch { /* keep raw text */ }
return parsed as T;
}
resetWorkerFailureCounter();
const text = await response.text();
if (text.length === 0) return undefined as unknown as T;
try {View on GitHub (pinned to 8bc631a71a)
Solutions
- Usually transient — the next hook event retries; confirm the warning does not repeat.
- Read the logged body snippet to find the worker-side error and fix that route.
- Reduce concurrent sessions/hook load against a single worker, or space out session starts.
- If 429 dominates, tune the worker's rate limits or increase the timeout budget so requests queue instead of rejecting.
Example fix
// before
const response = await workerHttpRequest(url, init);
if (!response.ok) throw new Error(`worker API failed: ${response.status}`);
// after
const response = await workerHttpRequest(url, init);
if (!response.ok && (response.status === 429 || response.status >= 500)) {
logger.warn('SYSTEM', `Worker API ${method} ${url} returned ${response.status}; skipping hook API call`, {
body: (await response.text().catch(() => '')).substring(0, 200),
});
return { continue: true, reason: `worker_api_${response.status}`, [WORKER_FALLBACK_BRAND]: true };
} Defensive patterns
Strategy: retry
Validate before calling
if (response.status === 429 || response.status >= 500) {
// transient — soft-fallback this event and let the next hook retry
return { continue: true, reason: `worker_api_${response.status}` };
} Type guard
const isTransientWorkerStatus = (status: number): boolean => status === 429 || status >= 500;
Try / catch
try {
const response = await workerHttpRequest(url, init);
if (isTransientWorkerStatus(response.status)) return softFallback(response.status);
return parseBody(await response.text());
} catch (e) {
// network-level failure to the local worker — same soft-fallback semantics
return { continue: true, reason: 'worker_api_unreachable' };
} Prevention
- Cap concurrent sessions/hook bursts against a single worker to stay under its rate limits.
- Watch the logged body snippet — a repeated 500 points to a worker route bug, not load.
- Treat 429/5xx as retriable-by-next-event; only investigate when warnings cluster.
When it happens
Trigger: POST/GET to a worker endpoint returns 429 (worker-side rate limiting) or 5xx (exception inside a worker route handler) — e.g., a burst of concurrent hook calls, or a thrown error in the route serving method+url.
Common situations: Many parallel Claude sessions hammering one worker; a worker route bug throwing 500; backpressure while summarization/observation queue is saturated.
Related errors
- Generator paused for ${abortCategory}; preserving buffered w
- Transcript path missing or file does not exist: ${transcript
- Transcript file exists but is empty: ${transcriptPath}
- Invalid mode inheritance: ${modeId}. Only one level of inher
- Invalid mode ID: ${modeId}
AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20).
Data as JSON: /api/errors/1f9a6cc39bfb55f6.
Report an issue: GitHub.