thedotmack/claude-mem · error · HostObserverUnavailableError
CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} is occupied by a
Error message
CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} is occupied by a process that is not an OpenAI-compatible observer. Stop that process or point CLAUDE_MEM_HOST_OBSERVER_PORT at your observer. What it means
When CLAUDE_MEM_HOST_OBSERVER_PORT is set, the port must host an OpenAI-compatible endpoint (the probe hits /v1/models and /v1/chat/completions and checks the response shape). If something answers but is not an observer — or the port refuses a bind test during the sync probe — claude-mem refuses to use it rather than misidentifying the service.
Source
Thrown at src/npx-cli/cmem-memory-credentials.ts:249
): string {
const worker = parsePort(typeof workerPort === 'number' ? workerPort : nonEmptyString(workerPort));
const configuredRaw = nonEmptyString(env.CLAUDE_MEM_HOST_OBSERVER_PORT);
if (configuredRaw) {
const configured = parsePort(configuredRaw);
if (configured == null) {
throw new HostObserverUnavailableError(
`CLAUDE_MEM_HOST_OBSERVER_PORT=${configuredRaw} is not a valid port. Set it to the port your OpenAI-compatible observer already listens on.`,
);
}
if (worker != null && configured === worker) {
throw new HostObserverUnavailableError(
`CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} is the claude-mem worker port. Point it at your OpenAI-compatible observer instead.`,
);
}
const status = probe(configured);
if (status === 'observer') return String(configured);
if (status === 'occupied') {
throw new HostObserverUnavailableError(
`CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} is occupied by a process that is not an OpenAI-compatible observer. Stop that process or point CLAUDE_MEM_HOST_OBSERVER_PORT at your observer.`,
);
}
throw new HostObserverUnavailableError(
`CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} has nothing listening. Start your OpenAI-compatible observer on that port, then rerun with --provider host.`,
);
}
const candidates = hostObserverCandidatePorts(workerPort, env);
for (const port of candidates) {
const status = probe(port);
if (status === 'observer') return String(port);
}
throw new HostObserverUnavailableError(
`No OpenAI-compatible host observer is listening on 127.0.0.1:${candidates.join(' or ') || HOST_OBSERVER_DEFAULT_PORT}. Host mode uses an observer you already run; claude-mem does not start one. Start your observer, then rerun with --provider host. If it uses another port, set CLAUDE_MEM_HOST_OBSERVER_PORT.`,
);
}View on GitHub (pinned to 8bc631a71a)
Solutions
- Stop the process occupying that port (lsof -i :PORT, then kill it), and rerun the install
- Find your observer's real API port and set CLAUDE_MEM_HOST_OBSERVER_PORT to it, e.g. export CLAUDE_MEM_HOST_OBSERVER_PORT=4141
- Verify the endpoint responds like OpenAI: curl -H 'Authorization: Bearer x' http://127.0.0.1:$CLAUDE_MEM_HOST_OBSERVER_PORT/v1/models should return a model list
- Unset CLAUDE_MEM_HOST_OBSERVER_PORT to let auto-discovery probe 37777/37778 instead
Example fix
// before export CLAUDE_MEM_HOST_OBSERVER_PORT=3000 # occupied by a dev server // after lsof -ti :3000 | xargs kill export CLAUDE_MEM_HOST_OBSERVER_PORT=4141 # actual observer port
Defensive patterns
Strategy: validation
Validate before calling
const res = await fetch(`http://127.0.0.1:${port}/v1/models`, { headers: { Authorization: 'Bearer x' } }).catch(() => null);
const body = res?.ok ? await res.text() : '';
if (!body.includes('data')) throw new Error(`Port ${port} is not an OpenAI-compatible observer`); Try / catch
try {
const port = resolveHostObserverPort(workerPort, env);
} catch (e) {
if (e instanceof HostObserverUnavailableError && e.message.includes('is occupied by a process')) {
// inspect/kill the squatter or reconfigure the port, then retry
} else throw e;
} Prevention
- Before installing, curl /v1/models on the configured port and confirm an OpenAI-style response
- Use lsof -i :PORT to confirm which process owns the port before pointing claude-mem at it
- Reserve dedicated ports for the observer so unrelated dev servers do not collide
When it happens
Trigger: resolveHostObserverPort probes the configured port; probeHostObserverPortSync returns 'occupied' because another process (a dev server, another app, a stale worker) is listening there and its responses do not look OpenAI-compatible.
Common situations: Port reused by a unrelated local web app; leftover process from a previous session squatting on the port; pointing at a UI port of a tool whose API is on a different port.
Related errors
- CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} is the claude-me
- CLAUDE_MEM_HOST_OBSERVER_PORT=${configured} has nothing list
- CLAUDE_MEM_HOST_OBSERVER_PORT=${configuredRaw} is not a vali
- No OpenAI-compatible host observer is listening on 127.0.0.1
- Provider=${options.provider} requested non-interactively. AP
AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-09-09).
Data as JSON: /api/errors/0ea0159e089e40bc.
Report an issue: GitHub.