nexu-io/open-design · error · Error

grok image fetch ${imgResp.status}

Error message

grok image fetch ${imgResp.status}

What it means

Thrown when xAI's image response uses the `url` delivery path (no b64_json) and the secondary fetch of that URL returns a non-2xx status. The request body asks for `response_format: 'b64_json'`, so reaching this branch means xAI ignored the format hint and returned a hosted URL that is now unreachable, expired, or access-gated.

Source

Thrown at apps/daemon/src/media/index.ts:1653

  }));
  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`,
    suggestedExt: sniffImageExt(bytes),
  };
}

async function renderNanoBananaImage(ctx: MediaContext, credentials: ProviderConfig): Promise<RenderResult> {
  const apiKey = credentials.apiKey;

View on GitHub (pinned to 5be4028344)

Solutions

  1. Retry the render — short-lived URL expiry is the most common cause and a fresh generation returns a fresh URL.
  2. Verify withMediaRequestInit propagates ctx auth/headers to the secondary fetch; if the URL is xAI-hosted it may need the bearer token.
  3. Check xAI status page for image-CDN incidents if the status is 5xx.
  4. If reproducible, force inline delivery by ensuring response_format:'b64_json' is honoured upstream, or pin credentials.baseUrl to the official endpoint.

Example fix

// before
const imgResp = await fetch(entry.url, withMediaRequestInit(ctx));
if (!imgResp.ok) throw new Error(`grok image fetch ${imgResp.status}`);

// after — one retry on transient host errors, then a clearer message
let imgResp = await fetch(entry.url, withMediaRequestInit(ctx));
if (!imgResp.ok && imgResp.status >= 500) {
  await sleep(1000);
  imgResp = await fetch(entry.url, withMediaRequestInit(ctx));
}
if (!imgResp.ok) {
  throw new Error(`grok image fetch ${imgResp.status} for ${truncate(entry.url, 80)}`);
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate the URL before fetching, and confirm it is still fresh
function isValidGrokImageUrl(u: unknown): u is string {
  return typeof u === 'string' && /^https?:\/\//.test(u) && u.length < 4096;
}

Type guard

function isFreshSignedUrl(u: string, maxAgeMs = 5 * 60_000): boolean {
  // xAI signed URLs sometimes embed an expiry; if present, ensure it is in the future
  const m = u.match(/[?&](?:exp|expires|X-Expiry)=(\d+)/);
  if (!m) return true; // unknown expiry — assume fresh
  return Number(m[1]) * 1000 > Date.now() + maxAgeMs;
}

Try / catch

let bytes: Buffer | undefined;
for (let attempt = 0; attempt < 2; attempt++) {
  try {
    const r = await fetch(entry.url, withMediaRequestInit(ctx));
    if (!r.ok) {
      if (attempt === 0 && (r.status >= 500 || r.status === 429)) continue;
      throw new Error(`grok image fetch ${r.status}`);
    }
    bytes = Buffer.from(await r.arrayBuffer());
    break;
  } catch (e) {
    if (attempt === 1) throw e;
  }
}

Prevention

When it happens

Trigger: xAI returns `{data:[{url:'https://...'}]}` and the URL (a) expired before the daemon fetched it, (b) requires the same bearer auth used for generation but withMediaRequestInit did not attach it, (c) lives behind a CDN that 403/404s requests without a referer, or (d) the host returned 5xx during a transient outage.

Common situations: Slow networks where the URL TTL lapses before download, corporate proxies stripping auth headers, xAI regional CDN incidents, or pointing baseUrl at a gateway that issues short-lived signed URLs.

Related errors


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