{"record":{"id":"98d88f35b6a50a06","repo":"thedotmack/claude-mem","slug":"worker-api-error-response-status-errortext","errorCode":null,"errorMessage":"Worker API error (${response.status}): ${errorText}","messagePattern":"Worker API error \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/servers/mcp-server.ts","lineNumber":99,"sourceCode":"    if (opts.body) {\n      response = await workerHttpRequest(endpoint, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify(opts.body)\n      });\n    } else {\n      const searchParams = new URLSearchParams();\n      for (const [key, value] of Object.entries(opts.query ?? {})) {\n        if (value !== undefined && value !== null) {\n          searchParams.append(key, String(value));\n        }\n      }\n      response = await workerHttpRequest(`${endpoint}?${searchParams}`);\n    }\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      throw new Error(`Worker API error (${response.status}): ${errorText}`);\n    }\n\n    logger.debug('SYSTEM', '← Worker API success', undefined, { endpoint });\n\n    if (opts.text) {\n      return { content: [{ type: 'text' as const, text: await response.text() }] };\n    }\n    if (opts.body) {\n      return { content: [{ type: 'text' as const, text: JSON.stringify(await response.json(), null, 2) }] };\n    }\n    return await response.json() as { content: Array<{ type: 'text'; text: string }>; isError?: boolean };\n  } catch (error: unknown) {\n    logger.error('SYSTEM', '← Worker API error', { endpoint }, error instanceof Error ? error : new Error(String(error)));\n    return {\n      content: [{\n        type: 'text' as const,\n        text: `Error calling Worker API: ${error instanceof Error ? error.message : String(error)}`\n      }],","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/servers/mcp-server.ts#L81-L117","documentation":"callWorker is the MCP server's HTTP client to the local claude-mem worker API. When the worker responds with a non-2xx status, it reads the response body and throws `Worker API error (<status>): <body>` so the underlying reason (404, 500, validation text, etc.) is preserved in the message. The throw is caught inside callWorker and surfaced to the MCP client as an isError tool result with the same text, so callers usually see it as an error-content response rather than an uncaught exception.","triggerScenarios":"Any tool handler calling callWorker (e.g. handleSessionStartContext, search/timeline tools) while the worker HTTP endpoint returns non-ok: worker not fully started, worker crashed mid-request, unknown endpoint path, worker port mismatch, or the worker returning 4xx/5xx for the given query/body.","commonSituations":"Stale worker process from a previous plugin version still bound to the port; worker killed by OOM or machine sleep so requests hit a dead socket or half-updated route; MCP server and worker version skew after an upgrade leaving an endpoint the running worker doesn't implement; malformed tool arguments producing a 400/500 from the worker.","solutions":["Inspect the status and body text after 'Worker API error' — it contains the worker's own error reason.","Restart the worker: run `claude-mem status` / restart the plugin so ensureWorkerStarted respawns a fresh worker matching the current build.","Check the worker is listening on the expected port (getWorkerPort) and that no stale process occupies it; kill leftover worker processes and retry.","If the status is 404 after an upgrade, align MCP server and worker versions (rebuild/reinstall the plugin).","Retry the tool call once the worker responds; the error is transient in most crash/staleness cases."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Probe worker availability before issuing the real call\nconst health = await fetch(`http://127.0.0.1:${getWorkerPort()}/health`).catch(() => null);\nif (!health || !health.ok) throw new Error('worker not ready; restart claude-mem worker');","typeGuard":null,"tryCatchPattern":"try {\n  return await callWorker('/api/search', { query: { q } });\n} catch (err) {\n  const msg = (err as Error).message;\n  const m = msg.match(/Worker API error \\((\\d+)\\)/);\n  if (m) {\n    const status = Number(m[1]);\n    if (status >= 500 || status === 503) await ensureWorkerStarted(); // respawn and retry once\n  }\n  return { content: [{ type: 'text', text: `worker call failed: ${msg}` }], isError: true };\n}","preventionTips":["Restart/rebuild the worker whenever the plugin version changes to avoid MCP-server/worker API skew.","Monitor for stale worker processes on the configured port and kill leftovers before restarting.","Add a health-check ping before batch tool operations.","Log the status + body from the error message; the worker's own text usually pinpoints the failing endpoint."],"tags":["http","worker","network","mcp"],"backgroundTag":"http-error-response","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}