nexu-io/open-design · error · Error
openai non-JSON response: ${truncate(text, 200)}
Error message
openai non-JSON response: ${truncate(text, 200)} What it means
Thrown by renderOpenAIImage when resp.ok is true but JSON.parse(text) throws. The dispatcher assumes a JSON images/generations response; a non-JSON 200 usually means a man-in-the-middle (corporate proxy, captive portal, service mesh) returned an HTML page with a 200 status, or the baseUrl was pointed at an endpoint that does not speak the OpenAI schema.
Source
Thrown at apps/daemon/src/media/index.ts:959
const resp = await fetch(url, withMediaRequestInit(ctx, {
method: 'POST',
headers,
body: JSON.stringify(body),
dispatcher: ctx.requestInit.dispatcher
?? openAIImageDispatcher as unknown as NonNullable<RequestInit['dispatcher']>,
signal: AbortSignal.timeout(Math.max(OPENAI_IMAGE_HEADERS_TIMEOUT_MS, OPENAI_IMAGE_BODY_TIMEOUT_MS)),
}));
const text = await resp.text();
if (!resp.ok) {
const tag = azure ? 'azure-openai' : 'openai';
throw new Error(`${tag} ${resp.status}: ${truncate(text, 240)}`);
}
let data: any;
try {
data = JSON.parse(text);
} catch {
throw new Error(`openai non-JSON response: ${truncate(text, 200)}`);
}
const entry = data && Array.isArray(data.data) ? data.data[0] : null;
if (!entry) throw new Error('openai response had no data[0]');
let bytes;
if (entry.b64_json) {
bytes = Buffer.from(entry.b64_json, 'base64');
} else if (entry.url) {
const imgResp = await fetch(entry.url, withMediaRequestInit(ctx));
if (!imgResp.ok) throw new Error(`openai image fetch ${imgResp.status}`);
const arr = await imgResp.arrayBuffer();
bytes = Buffer.from(arr);
} else {
throw new Error('openai response had neither b64_json nor url');
}
const tag = azure ? 'azure-openai' : 'openai';
return {
bytes,View on GitHub (pinned to 5be4028344)
Solutions
- Inspect the truncated body in the message to identify what returned the non-JSON response (proxy page, gateway error, etc.).
- Verify credentials.baseUrl resolves to a real OpenAI/Azure endpoint and not a UI or docs host.
- Bypass or reconfigure the intercepting proxy for the OpenAI host, or point baseUrl at the proxy's true API path.
- If running a custom OpenAI-compatible server, ensure it returns application/json with the {data:[...]} schema on success.
Example fix
// before OD_OPENAI_BASE_URL=https://gateway.internal/ // after (point at the API path the gateway actually serves) OD_OPENAI_BASE_URL=https://gateway.internal/v1
Defensive patterns
Strategy: try-catch
Validate before calling
function isOpenAIJsonEndpoint(baseUrl: string): boolean {
// crude guard: must look like an API host, not a UI/docs host
return /^https:\/\/[\w.-]+\.openai\.com(?:\/.*)?$/.test(baseUrl)
|| /\/v1$/.test(baseUrl)
|| /openai\.azure\.com/.test(baseUrl);
} Try / catch
try {
return await renderOpenAIImage(ctx, credentials);
} catch (err) {
const m = err instanceof Error ? err.message : '';
if (m.startsWith('openai non-JSON response:')) {
// surface the body snippet to the user — almost always a proxy/gateway issue
throw new ConfigError(`OpenAI returned HTML/text, not JSON. Check baseUrl and proxies. Body: ${m}`);
}
throw err;
} Prevention
- Point baseUrl at the API host (e.g. https://api.openai.com/v1), never at a UI/docs host.
- Bypass TLS-intercepting proxies for the OpenAI host, or whitelist the API path on the proxy.
- Smoke-test the endpoint with curl before configuring the daemon.
When it happens
Trigger: Custom baseUrl pointed at a browser-facing gateway that returns HTML; corporate TLS-intercepting proxy injecting a block page; misconfigured reverse proxy returning a health-check page; baseUrl pointing at /v1 instead of the host root.
Common situations: Self-hosted gateway in front of OpenAI that 200s with HTML on unknown paths; Azure app-gateway rewrite rule stripping the body; local mock server returning text/plain.
Related errors
- openai response had no data[0]
- openai response had neither b64_json nor url
- ${providerTag} non-JSON response: ${truncate(text, 200)}
- ${tag} ${resp.status}: ${truncate(text, 240)}
- openai image fetch ${imgResp.status}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/00e9ec3297d92230.
Report an issue: GitHub.