nexu-io/open-design · error · Error
daemon ${resp.status} on ${url}: ${body || resp.statusText}
Error message
daemon ${resp.status} on ${url}: ${body || resp.statusText} What it means
Thrown by the generic getJson helper when a GET request returns a non-2xx status. The message includes the HTTP status, the URL, and either the response body (via safeText) or statusText. This is the catch-all transport error for read operations in the MCP layer (active context, project list, etc.).
Source
Thrown at apps/daemon/src/mcp.ts:3007
const subs = list.filter((p) =>
String(p.name || '').toLowerCase().includes(lower),
);
if (subs.length === 1) { const p = subs[0]!; return { id: p.id, name: p.name, source: 'substring' as const }; }
if (subs.length > 1) {
const opts = subs.map((p) => `${p.name} (${p.id})`).join(', ');
throw new Error(
`multiple projects match "${arg}": ${opts}. Pass the UUID instead.`,
);
}
throw new Error(`no project matches "${arg}"`);
}
async function getJson<T>(url: string, headers?: Record<string, string>): Promise<T> {
const resp = await fetch(url, headers ? { headers } : undefined);
if (!resp.ok) {
const body = await safeText(resp);
throw new Error(`daemon ${resp.status} on ${url}: ${body || resp.statusText}`);
}
return (await resp.json()) as T;
}
async function getFile(
baseUrl: string,
project: string,
relPath: string,
active: ActiveContext | null,
resolved?: ResolvedProject | null,
offset = 0,
limit = 2000,
headers?: Record<string, string>,
) {
const segments = String(relPath)
.split('/')
.filter((s) => s.length > 0)
.map(encodeURIComponent);View on GitHub (pinned to 5be4028344)
Solutions
- Read the embedded status code: 401/403 → fix auth headers; 404 → wrong URL or daemon version; 500 → check daemon logs; 429 → back off.
- Run `pnpm tools-dev status --json` and `pnpm tools-dev logs --json` to inspect daemon health and errors.
- Confirm the base URL and port match the running daemon.
- Update the daemon and MCP client to matching versions if an endpoint moved.
- For 5xx, restart the daemon via tools-dev and retry once.
Example fix
// before: 401 from missing auth header
getJson(`${baseUrl}/api/active`)
// after
getJson(`${baseUrl}/api/active`, { Authorization: `Bearer ${token}` }) Defensive patterns
Strategy: try-catch
Validate before calling
async function safeGetJson<T>(url: string, headers?: Record<string,string>): Promise<T> {
const resp = await fetch(url, headers ? { headers } : undefined);
if (!resp.ok) throw new Error(`daemon ${resp.status}`);
return await resp.json() as T;
} Try / catch
try {
return await getJson(url, headers);
} catch (e) {
const msg = String((e as Error).message);
if (/daemon 401|403/.test(msg)) await refreshAuth();
if (/daemon 5\d\d/.test(msg)) await waitForDaemon();
throw e;
} Prevention
- Wrap daemon reads in a helper that inspects status codes.
- Keep auth headers fresh and the daemon version matched to the client.
- Surface the embedded status/body to your logs for faster triage.
When it happens
Trigger: Daemon returns 4xx/5xx (e.g. 401 auth, 404 route, 500 internal); proxy returns an error page; the URL hit a removed/renamed endpoint; rate limiting (429).
Common situations: Missing or expired auth headers; daemon version mismatch where an endpoint was removed; daemon crashed and a reverse proxy served 502; CORS/network appliance injecting an error.
Related errors
- project arg omitted and active context lookup failed: ${erro
- collab cloud error ${status} (${code})
- elevenlabs voices ${resp.status}: ${errText.slice(0, 240)}
- The registered Open Design runtime is unavailable and cannot
- Open Design was launched headlessly but its daemon did not b
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/3b7154a90eb99b70.
Report an issue: GitHub.