nexu-io/open-design · error · Error
grok image response had no data[0]
Error message
grok image response had no data[0]
What it means
Thrown by renderGrokImage after a successful xAI /v1/images/generations call when the parsed JSON lacks a usable first entry. The code computes `entry = data.data[0]` only when `data.data` is an Array; anything else (an object, a string, or a missing field) yields null and trips this guard. It signals an upstream response-shape contract violation rather than a network or auth failure.
Source
Thrown at apps/daemon/src/media/index.ts:1647
method: 'POST',
headers: {
'authorization': `Bearer ${credentials.apiKey}`,
'content-type': 'application/json',
},
body: JSON.stringify(body),
}));
const text = await resp.text();
if (!resp.ok) {
throw new Error(`grok image ${resp.status}: ${truncate(text, 240)}`);
}
let data: any;
try {
data = JSON.parse(text);
} catch {
throw new Error(`grok image non-JSON: ${truncate(text, 200)}`);
}
const entry = data && Array.isArray(data.data) ? data.data[0] : null;
if (!entry) throw new Error('grok image 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(`grok image fetch ${imgResp.status}`);
bytes = Buffer.from(await imgResp.arrayBuffer());
} else {
throw new Error('grok image response missing b64_json/url');
}
// xAI's Imagine returns JPEG by default (no format option in the API
// surface), but PNG/WebP are technically possible. Sniff the magic
// bytes so the on-disk extension matches reality — saving JPEG bytes
// as `.png` confuses Finder previews and any downstream consumer that
// trusts the extension.
return {
bytes,
providerNote: `grok/${ctx.wireModel} · ${aspectRatio} · ${bytes.length} bytes`,View on GitHub (pinned to 5be4028344)
Solutions
- Inspect the truncated upstream body the daemon logged alongside this error to see the actual envelope xAI returned.
- Confirm ctx.wireModel is still a valid xAI image model id (grok-2-image family) and that the account has Imagine access.
- If a proxy is set in credentials.baseUrl, point it back at https://api.x.ai/v1 or update the proxy to pass the response through unchanged.
- If xAI genuinely changed the schema, extend the `entry` extraction in apps/daemon/src/media/index.ts:1646 to handle the new shape.
- Retry once — transient empty-result envelopes have been seen during xAI incidents.
Example fix
// before
const entry = data && Array.isArray(data.data) ? data.data[0] : null;
if (!entry) throw new Error('grok image response had no data[0');
// after — surface the real envelope so the operator can diagnose
const list = data?.data;
const entry = Array.isArray(list) ? list[0] : null;
if (!entry) {
throw new Error(
`grok image response had no data[0]: ${truncate(JSON.stringify(data), 200)}`,
);
} Defensive patterns
Strategy: validation
Validate before calling
// Validate xAI image response shape before consuming data[0]
function assertGrokImageEnvelope(data: unknown): asserts data is { data: { b64_json?: string; url?: string }[] } {
if (!data || typeof data !== 'object') {
throw new Error(`grok image: response is not an object (${typeof data})`);
}
const d = data as any;
if (d.error) {
throw new Error(`grok image upstream error: ${JSON.stringify(d.error)}`);
}
if (!Array.isArray(d.data) || d.data.length === 0) {
throw new Error(`grok image: data[] missing/empty; keys=${Object.keys(d).join(',')}`);
}
} Type guard
function isGrokImageEntry(v: unknown): v is { b64_json?: string; url?: string } {
return typeof v === 'object' && v !== null && (
typeof (v as any).b64_json === 'string' || typeof (v as any).url === 'string'
);
} Try / catch
try {
const entry = assertGrokImageEnvelope(data) && data.data[0];
// ...
} catch (e) {
// log full `data` once, then surface a trimmed error to the user
ctx.onProviderRequestSettled?.({ providerId: 'grok', ok: false, error: String(e) });
throw e;
} Prevention
- Always assert the envelope shape before indexing data[0]; never trust the array exists.
- Log the full upstream body once when extraction fails so future shape changes are diagnosable.
- Treat a 200 with an `error` field as a failure rather than falling through to data[0].
- Pin ctx.wireModel to a known image-capable xAI slug and validate it in the provider registry.
When it happens
Trigger: xAI returns a 200 whose body is an error envelope (e.g. `{error: {...}}`) instead of the OpenAI-style `{data:[...]}`, returns `data` as an object instead of an array, returns an empty `data: []` (n=0 effective), or xAI ships a new response schema that drops the `data` array wrapper.
Common situations: Hitting the Grok Imagine endpoint with a model slug xAI deprecated/renamed (200 with a soft error body), pointing credentials.baseUrl at a non-xAI proxy that re-shapes responses, or xAI A/B-testing a new envelope during a launch window.
Related errors
- grok image response missing b64_json/url
- grok image fetch ${imgResp.status}
- nano-banana image non-JSON: ${truncate(text, 200)}
- nano-banana image response missing candidates[].content.part
- openrouter image non-JSON response: ${truncate(text, 200)}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/bd96bfba88d29ea3.
Report an issue: GitHub.