nexu-io/open-design · error · Error
${providerTag} non-JSON response: ${truncate(text, 200)}
Error message
${providerTag} non-JSON response: ${truncate(text, 200)} What it means
Thrown by parseOpenAICompatibleJson when resp.ok is true but the body is not parseable as JSON. Same shape as the first-party 'openai non-JSON response' but for any provider routed through the shared helper. The providerTag prefix identifies which integration returned the bad body.
Source
Thrown at apps/daemon/src/media/index.ts:1133
function customImageOverridesOpenAIModel(
ctx: MediaContext,
credentials: ProviderConfig | null,
): credentials is ProviderConfig {
const baseUrl = credentials?.baseUrl?.trim();
const model = credentials?.model?.trim();
if (!baseUrl || !model) return false;
return model === ctx.model || model === ctx.wireModel;
}
async function parseOpenAICompatibleJson(resp: Response, providerTag: string): Promise<any> {
const text = await resp.text();
if (!resp.ok) {
throw new Error(`${providerTag} ${resp.status}: ${truncate(text, 240)}`);
}
try {
return JSON.parse(text);
} catch {
throw new Error(`${providerTag} non-JSON response: ${truncate(text, 200)}`);
}
}
async function bytesFromOpenAICompatibleData(data: any, providerTag: string, requestInit: MediaRequestInit = {}): Promise<Buffer> {
const entry = data && Array.isArray(data.data) ? data.data[0] : null;
if (!entry) throw new Error(`${providerTag} response had no data[0]`);
if (typeof entry.b64_json === 'string' && entry.b64_json) {
const raw = entry.b64_json.includes(',')
? entry.b64_json.slice(entry.b64_json.indexOf(',') + 1)
: entry.b64_json;
return Buffer.from(raw, 'base64');
}
if (typeof entry.url === 'string' && entry.url) {
const mediaResp = await fetch(entry.url, requestInit);
if (!mediaResp.ok) {
throw new Error(`${providerTag} media fetch ${mediaResp.status}`);
}
const arr = await mediaResp.arrayBuffer();View on GitHub (pinned to 5be4028344)
Solutions
- Inspect the inlined body snippet to identify what is returning non-JSON (HTML page, plain text, SSE chunk).
- Point baseUrl at the gateway's JSON API root, not its UI or docs host.
- Bypass or reconfigure intercepting proxies for the gateway host.
- If the gateway streams, switch to a model/endpoint that returns a single JSON body, or extend the renderer to parse the stream.
Example fix
// before OD_IMAGEROUTER_BASE_URL=https://imagerouter.io/ // after (API root, not marketing site) OD_IMAGEROUTER_BASE_URL=https://api.imagerouter.io/v1/openai
Defensive patterns
Strategy: try-catch
Validate before calling
function isCompatibleJsonEndpoint(baseUrl: string): boolean {
return /\/v\d+$/.test(baseUrl) || /api\./.test(baseUrl);
} Try / catch
try {
return await parseOpenAICompatibleJson(resp, providerTag);
} catch (err) {
const m = err instanceof Error ? err.message : '';
if (m.includes('non-JSON response')) {
throw new ConfigError(`${providerTag} returned non-JSON. Check baseUrl and intercepting proxies. Body: ${m}`);
}
throw err;
} Prevention
- Point baseUrl at the gateway's API JSON root, not its UI or docs host.
- Bypass TLS-intercepting proxies for the gateway host or whitelist its API path.
- Confirm the gateway returns a single JSON document, not an SSE stream.
When it happens
Trigger: Gateway returns an HTML block/landing page with HTTP 200; corporate proxy intercepts and rewrites the response; baseUrl points at a browser UI rather than the API; the gateway returns SSE or plain text on success for some models.
Common situations: Wrong baseUrl host; TLS-intercepting proxy; gateway that streams responses instead of returning a single JSON document.
Related errors
- openai non-JSON response: ${truncate(text, 200)}
- ${providerTag} response had no data[0]
- ${providerTag} response had neither b64_json nor url
- openai response had no data[0]
- openai response had neither b64_json nor url
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/40847f39b47b7c94.
Report an issue: GitHub.