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
- Retry the render — short-lived URL expiry is the most common cause and a fresh generation returns a fresh URL.
- Verify withMediaRequestInit propagates ctx auth/headers to the secondary fetch; if the URL is xAI-hosted it may need the bearer token.
- Check xAI status page for image-CDN incidents if the status is 5xx.
- 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
- Prefer response_format:'b64_json' so no secondary fetch is needed; only fall back to URL when inline is unavailable.
- Fetch the URL immediately after receiving it — signed URLs have short TTLs.
- Carry ctx auth/headers into the secondary fetch in case the host requires them.
- Retry once on 5xx/429 before surfacing the error to the user.
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
- grok image response had no data[0]
- grok image response missing b64_json/url
- openrouter image download ${imgResp.status}
- grok image non-JSON: ${truncate(text, 200)}
- nano-banana image non-JSON: ${truncate(text, 200)}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/27c074ae611c5db1.
Report an issue: GitHub.