thedotmack/claude-mem · error

Worker API error (${response.status}): ${errorText}

Error message

Worker API error (${response.status}): ${errorText}

What it means

Thrown by callWorker() inside the MCP server whenever the local worker HTTP endpoint returns a non-2xx response. The message embeds the raw HTTP status code and the response body text so the underlying worker error (auth, validation, 500, etc.) is surfaced verbatim. It is a generic relay of any worker-side failure to the MCP tool caller.

Source

Thrown at src/servers/mcp-server.ts:98

    if (opts.body) {
      response = await workerHttpRequest(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(opts.body)
      });
    } else {
      const searchParams = new URLSearchParams();
      for (const [key, value] of Object.entries(opts.query ?? {})) {
        if (value !== undefined && value !== null) {
          searchParams.append(key, String(value));
        }
      }
      response = await workerHttpRequest(`${endpoint}?${searchParams}`);
    }

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Worker API error (${response.status}): ${errorText}`);
    }

    logger.debug('SYSTEM', '← Worker API success', undefined, { endpoint });

    if (opts.text) {
      return { content: [{ type: 'text' as const, text: await response.text() }] };
    }
    if (opts.body) {
      return { content: [{ type: 'text' as const, text: JSON.stringify(await response.json(), null, 2) }] };
    }
    return await response.json() as { content: Array<{ type: 'text'; text: string }>; isError?: boolean };
  } catch (error: unknown) {
    logger.error('SYSTEM', '← Worker API error', { endpoint }, error instanceof Error ? error : new Error(String(error)));
    return {
      content: [{
        type: 'text' as const,
        text: `Error calling Worker API: ${error instanceof Error ? error.message : String(error)}`
      }],

View on GitHub (pinned to d768ba3643)

Solutions

  1. Read the embedded status code and errorText — that is the real error; fix the worker-side cause it names (e.g. unknown corpus, corrupt DB).
  2. Confirm the worker is healthy: call GET /api/health and GET /api/readiness via workerHttpRequest; if either is non-OK, run ensureWorkerConnection() / restart the worker before retrying.
  3. Verify WORKER_SCRIPT_PATH resolves to the current built bundle and the port from getWorkerPort() matches the running listener.
  4. Reproduce the exact endpoint+payload the tool sent and call the worker route directly to isolate MCP-layer vs worker-layer faults.

Example fix

// before — error swallowed, only the relayed text seen
callWorker('/api/corpus/unknown/prime', { body: {} });
// returns { content:[{text:'Error calling Worker API: Worker API error (404): corpus not found'}], isError:true }

// after — surface status explicitly so callers can branch
if (!response.ok) {
  const errorText = await response.text();
  const err = new Error(`Worker API error (${response.status}): ${errorText}`);
  (err as any).status = response.status;
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling a worker-backed tool, confirm the worker is up.
const health = await workerHttpRequest('/api/health');
if (!health.ok) {
  throw new Error(`Worker unhealthy (status ${health.status}); aborting tool call`);
}

Try / catch

// callWorker already wraps in try/catch and returns {content, isError:true}.
// At the tool boundary, branch on isError:
const result = await callWorker('/api/search', { query: args });
if (result.isError) {
  // result.content[0].text holds 'Error calling Worker API: Worker API error (NNN): ...'
  const m = result.content[0].text.match(/error \((\d+)\)/);
  const status = m ? Number(m[1]) : null;
  if (status && status >= 500) { /* transient — retry */ }
  if (status === 404) { /* not found — handle */ }
}

Prevention

When it happens

Trigger: Any MCP tool that delegates to callWorker() (search, timeline, get_observations, the corpus tools, session_start_context) will trigger this when the worker responds with status >= 400. Concretely: POST /api/corpus/<name>/prime with an unknown corpus name (404), GET /api/search?... when the worker's SQLite/Chroma is corrupt (500), or any endpoint when the worker process is mid-restart and returns 503.

Common situations: Worker bundle is stale (rebuilt from old source after an upgrade), worker port mismatch between getWorkerPort() and the actual listener, malformed tool arguments that pass MCP schema validation but fail worker-level validation, or the worker's backing store (SQLite file locked, Chroma offline) is unhealthy.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/98d88f35b6a50a06. Report an issue: GitHub.