thedotmack/claude-mem · error · Error
Request timed out after
Error message
Request timed out after ${timeoutMs}ms What it means
fetchWithTimeout wraps workerFetch with AbortSignal.timeout(timeoutMs). When the fetch aborts with a DOMException named 'TimeoutError', the DOMException (whose text is runtime-dependent) is normalized into the stable message 'Request timed out after <N>ms' so callers like hook-command.ts and server-beta-client.ts can match on the text reliably.
Solutions
- Check the worker is alive and responsive (`claude-mem status` / worker logs); restart it if hung
- Increase the timeoutMs passed to fetchWithTimeout/workerHttpRequest for heavy requests
- Add retry-with-backoff around the call for transient slowness, and match the stable 'Request timed out after' message in catch blocks
Example fix
// before
const res = await workerHttpRequest('/hooks', init, 1000); // too tight
// after
const res = await withRetry(() => workerHttpRequest('/hooks', init, 10000), { retries: 2 });
// catch (e) { if (e.message.includes('Request timed out after')) ... } Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
function isTimeoutError(e: unknown): boolean {
return e instanceof Error && e.message.includes('Request timed out after');
} Try / catch
try {
return await fetchWithTimeout(url, init, timeoutMs);
} catch (e) {
if (isTimeoutError(e)) {
await sleep(backoffMs);
return await fetchWithTimeout(url, init, timeoutMs * 2); // retry once with a larger budget
}
throw e;
} Prevention
- Set timeoutMs generously relative to the heaviest expected worker request
- Monitor worker health/restart it when requests start timing out
- Match on the stable 'Request timed out after' message rather than DOMException text
When it happens
Trigger: workerHttpRequest -> fetchWithTimeout with a timeoutMs deadline, and the worker HTTP request does not complete before AbortSignal.timeout fires: the worker process is hung, slow, or not draining its HTTP handler.
Common situations: claude-mem worker busy or deadlocked so requests queue; very short timeoutMs for a heavy hook request; machine under load or the Chroma service the worker proxies to is slow.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- [claude-mem] Worker GET
- [claude-mem] Worker GET
- [claude-mem] Worker POST
- Graceful shutdown deadline exceeded — proceeding
- Live PID detected but worker did not become ready before…
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/e51d63f56b3317a8.
Report an issue: GitHub.
Appendix: source
Thrown at src/shared/worker-utils.ts:156
} catch (err: unknown) {
if (isWorkerFetchVerboseEnabled()) {
logVerboseFetchFailure(url, init, err);
}
throw err;
}
}
export async function fetchWithTimeout(url: string, init: RequestInit = {}, timeoutMs: number): Promise<Response> {
try {
// AbortSignal.timeout (Node 18+) replaces the manual setTimeout/clearTimeout
// race. On expiry it aborts with a TimeoutError DOMException.
return await workerFetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
} catch (err: unknown) {
// Preserve the historical timeout-error message ("...timed out...") that
// callers match on (hook-command.ts, server-beta-client.ts) — the
// DOMException text is runtime-dependent, so normalize it here.
if (err instanceof DOMException && err.name === 'TimeoutError') {
throw new Error(`Request timed out after ${timeoutMs}ms`);
}
throw err;
}
}
let cachedPort: number | null = null;
let cachedHost: string | null = null;
let cachedSettings: SettingsDefaults | null = null;
let cachedApiRequestTimeoutMs: number | null = null;
function getWorkerSettingsPath(): string {
return path.join(SettingsDefaultsManager.get('CLAUDE_MEM_DATA_DIR'), 'settings.json');
}
function getWorkerSettings(): SettingsDefaults {
if (cachedSettings !== null) {
return cachedSettings;
}View on GitHub (pinned to d8bc9755e7)