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

  1. Inspect the truncated upstream body the daemon logged alongside this error to see the actual envelope xAI returned.
  2. Confirm ctx.wireModel is still a valid xAI image model id (grok-2-image family) and that the account has Imagine access.
  3. 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.
  4. If xAI genuinely changed the schema, extend the `entry` extraction in apps/daemon/src/media/index.ts:1646 to handle the new shape.
  5. 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

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


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/bd96bfba88d29ea3. Report an issue: GitHub.