{"record":{"id":"1f9a6cc39bfb55f6","repo":"thedotmack/claude-mem","slug":"worker-api-method-url-returned-response-st","errorCode":null,"errorMessage":"Worker API ${method} ${url} returned ${response.status}; skipping hook API call","messagePattern":"Worker API (.+?) (.+?) returned (.+?); skipping hook API call","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/shared/worker-utils.ts","lineNumber":879,"sourceCode":"  if (options.timeoutMs !== undefined) {\n    init.timeoutMs = options.timeoutMs;\n  }\n\n  let response: Response;\n  try {\n    response = await workerHttpRequest(url, init);\n  } catch (error) {\n    if (!boundedStartup) throw error;\n    logger.debug('SYSTEM', 'Worker unavailable for best-effort hook call', {\n      error: error instanceof Error ? error.message : String(error),\n    });\n    return { continue: true, reason: 'worker_unreachable', [WORKER_FALLBACK_BRAND]: true };\n  }\n  if (!response.ok) {\n    const text = await response.text().catch(() => '');\n    resetWorkerFailureCounter();\n    if (response.status === 429 || response.status >= 500) {\n      logger.warn('SYSTEM', `Worker API ${method} ${url} returned ${response.status}; skipping hook API call`, {\n        body: text.substring(0, 200),\n      });\n      return {\n        continue: true,\n        reason: `worker_api_${response.status}`,\n        [WORKER_FALLBACK_BRAND]: true,\n      };\n    }\n\n    let parsed: unknown = text;\n    try { parsed = JSON.parse(text); } catch { /* keep raw text */ }\n    return parsed as T;\n  }\n\n  resetWorkerFailureCounter();\n  const text = await response.text();\n  if (text.length === 0) return undefined as unknown as T;\n  try {","sourceCodeStart":861,"sourceCodeEnd":897,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/8bc631a71a487424b866756e43a6efa4574cc66b/src/shared/worker-utils.ts#L861-L897","documentation":"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.","triggerScenarios":"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.","commonSituations":"Many parallel Claude sessions hammering one worker; a worker route bug throwing 500; backpressure while summarization/observation queue is saturated.","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."],"exampleFix":"// before\nconst response = await workerHttpRequest(url, init);\nif (!response.ok) throw new Error(`worker API failed: ${response.status}`);\n\n// after\nconst response = await workerHttpRequest(url, init);\nif (!response.ok && (response.status === 429 || response.status >= 500)) {\n  logger.warn('SYSTEM', `Worker API ${method} ${url} returned ${response.status}; skipping hook API call`, {\n    body: (await response.text().catch(() => '')).substring(0, 200),\n  });\n  return { continue: true, reason: `worker_api_${response.status}`, [WORKER_FALLBACK_BRAND]: true };\n}","handlingStrategy":"retry","validationCode":"if (response.status === 429 || response.status >= 500) {\n  // transient — soft-fallback this event and let the next hook retry\n  return { continue: true, reason: `worker_api_${response.status}` };\n}","typeGuard":"const isTransientWorkerStatus = (status: number): boolean =>\n  status === 429 || status >= 500;","tryCatchPattern":"try {\n  const response = await workerHttpRequest(url, init);\n  if (isTransientWorkerStatus(response.status)) return softFallback(response.status);\n  return parseBody(await response.text());\n} catch (e) {\n  // network-level failure to the local worker — same soft-fallback semantics\n  return { continue: true, reason: 'worker_api_unreachable' };\n}","preventionTips":["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."],"tags":["worker-api","http-429","http-5xx","soft-fallback","claude-mem"],"backgroundTag":"http-server-error","analyzedSha":"8bc631a71a487424b866756e43a6efa4574cc66b","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}