BUG OpenRouter provider: worker fetch fails while identical Bun fetch succeeds
Environment
- claude-mem: 13.24.23
- Bun: 1.4.2
- OS: macOS
- Provider:
openrouter(custom OpenAI-compatible endpoint, not openrouter.ai) - Base URL:
http://192.168.178.166:11434/v1(remote Ollama instance) - Model:
llama3.1:8b
Problem
The worker's OpenRouter provider fails on every attempt to reach a self-hosted OpenAI-compatible endpoint (Ollama), immediately and consistently, with:
OpenRouter network error: Was there a typo in the url or port?
This is the t.cause.message surfaced by Bun when fetch() rejects with no
HTTP response ever received (see y4's e===void 0 branch in
worker-service.cjs). The failure happens in ~150-400ms — far too fast to be
the configured CLAUDE_MEM_LLM_TIMEOUT_MS=300000.
It persists identically across a full npx claude-mem restart (new PID,
same config, same immediate failure).
What works against the exact same endpoint
| Test | Result |
|---|---|
GET /v1/models via curl |
200 |
POST /v1/chat/completions via curl |
200 |
Standalone Bun script, plain fetch() |
200 |
Bun script run as a detached background process (spawn(..., {detached:true, stdio:'ignore'}), PPID reparented to 1, matching the worker's real spawn pattern when setsid is unavailable) |
200 |
Literal replica of the bundle's own request path — verbatim-copied tbe (URL builder), rbe (headers), g$t (body), nbe (400-retry wrapper), fetchChatCompletion, and aR (outer retry/AbortController wrapper), fed the real values from ~/.claude-mem/settings.json, run standalone outside the worker |
200, valid JSON response, AbortSignal aborted=false at call time |
Only the actual running worker process fails. The replica above was run concurrently with the live worker, against the same endpoint, at the same time the worker was failing in its logs.
What was excluded as a cause
- DNS / IPv4 vs IPv6 resolution differences
- Bun version mismatch (verified same
Bun.versionin worker and tests) - Proxy / env vars (
HTTP_PROXY,HTTPS_PROXY,NO_PROXY,NODE_TLS_REJECT_UNAUTHORIZED— none set, and grep confirms none of these are read on the OpenRouter code path) - Global fetch/http/https overrides, custom dispatcher/agent (
undici,setGlobalDispatcher,ProxyAgent,new Agent(— zero matches in the provider's actual code path) - Request payload/headers/size (large realistic 122KB payload with real headers tested standalone, succeeded)
- Concurrency (6 simultaneous standalone requests, all succeeded)
- AbortSignal reuse/already-aborted state (confirmed
aborted=falseat the moment of the real call in the literal replica) - Timeout (
CLAUDE_MEM_LLM_TIMEOUT_MS=300000; real failures occur in ~150-400ms) - Stale worker state (fresh restart, new PID, fails identically)
Relevant code paths (worker-service.cjs, 13.24.23)
- URL builder:
tbe(t) - Headers:
rbe(t,e) - Body:
g$t(t) - Fetch call site:
fetchChatCompletion(...), uses the plain globalfetch - Retry wrapper:
aR(t,e)— creates a freshAbortControllerper attempt - Error classifier:
y4,e===void 0branch produces the exact observed message
Ask
We're not asking for Ollama support — a custom OpenAI-compatible base URL is
already configurable and works from every reproduction outside the worker.
What we could not find is a reproducible difference in the code between the
working standalone path and the failing in-worker path. We'd appreciate any
pointers on what's different about the worker process's actual execution
context for fetch() (spawn env, detached-process behavior, something
specific to how the worker is actually launched in production vs. our
reproduction) that could explain this discrepancy.
Not related to any third-party launcher/wrapper — reproduced with the
standalone claude-mem CLI/worker only.
Source: thedotmack/claude-mem