nexu-io/open-design · error · Error
leonardo.ai image fetch ${imgResp.status}
Error message
leonardo.ai image fetch ${imgResp.status} What it means
Thrown after a successful generation when the GET to download the generated image bytes from imageUrl returned a non-2xx status. The image URL comes from generation.generated_images[0].url (a Leonardo CDN link). The message reports the raw HTTP status so you can distinguish auth (401/403) from gone (404/410) from CDN 5xx.
Source
Thrown at apps/daemon/src/media/index.ts:2289
if (generation?.status === 'COMPLETE') {
const images = generation?.generated_images;
if (Array.isArray(images) && images.length > 0) {
imageUrl = images[0]?.url;
break;
}
} else if (generation?.status === 'FAILED') {
throw new Error('leonardo.ai generation failed');
}
}
if (!imageUrl) {
throw new Error('leonardo.ai generation timed out after 2 minutes');
}
// Fetch the generated image
const imgResp = await fetch(imageUrl, withMediaRequestInit(ctx));
if (!imgResp.ok) {
throw new Error(`leonardo.ai image fetch ${imgResp.status}`);
}
const bytes = Buffer.from(await imgResp.arrayBuffer());
return {
bytes,
providerNote: `leonardo.ai/${ctx.model} · ${ctx.aspect} · ${bytes.length} bytes`,
suggestedExt: sniffImageExt(bytes),
};
}
async function renderGrokVideo(ctx: MediaContext, credentials: ProviderConfig, onProgress?: ProgressFn): Promise<RenderResult> {
if (!credentials.apiKey) {
throw new Error(
'no xAI credentials — sign in with your SuperGrok subscription (in OD or via `hermes auth add xai-oauth`), set XAI_API_KEY, or configure a key in Settings',
);
}View on GitHub (pinned to 5be4028344)
Solutions
- Retry the render — expired signed URLs and CDN 5xx usually resolve on a second attempt.
- If 404/410: the generated image was purged before download — re-run the generation.
- Verify daemon host can reach the Leonardo image CDN (network egress rules).
- If persistent, file a Leonardo support ticket — image lost between generation and storage is an upstream defect.
Example fix
// before
const imgResp = await fetch(imageUrl, withMediaRequestInit(ctx));
if (!imgResp.ok) {
throw new Error(`leonardo.ai image fetch ${imgResp.status}`);
}
// after — retry transient failures before throwing
async function fetchImageBytes(url: string, attempts = 3): Promise<Buffer> {
for (let i = 0; i < attempts; i++) {
const r = await fetch(url);
if (r.ok) return Buffer.from(await r.arrayBuffer());
if (r.status >= 500 && i < attempts - 1) { await new Promise(res => setTimeout(res, 1500 * (i + 1))); continue; }
throw new Error(`leonardo.ai image fetch ${r.status}`);
}
throw new Error('leonardo.ai image fetch exhausted retries');
} Defensive patterns
Strategy: retry
Try / catch
// Image fetch failures are dominated by transient CDN 5xx and expired signed
// URLs — retry with backoff, bail on 4xx that won't self-heal.
async function fetchLeonardoImage(url: string, attempts = 3): Promise<Buffer> {
let last: Error | null = null;
for (let i = 0; i < attempts; i++) {
const r = await fetch(url);
if (r.ok) return Buffer.from(await r.arrayBuffer());
last = new Error(`leonardo.ai image fetch ${r.status}`);
if (r.status >= 500 && i < attempts - 1) { await new Promise(res => setTimeout(res, 1500 * (i + 1))); continue; }
break;
}
throw last!;
} Prevention
- Download image bytes immediately on COMPLETE — do not enqueue or pause between poll completion and fetch, signed URLs expire.
- Whitelist Leonardo's image CDN host in daemon egress rules, not just the API host.
- Log the imageUrl host on fetch failure to correlate which CDN region is failing.
When it happens
Trigger: Generation completed, imageUrl extracted, but fetch(imageUrl, withMediaRequestInit(ctx)) returns imgResp.ok === false. Happens when the Leonardo CDN link expired between completion and download, when CDN has a transient 5xx, or when egress to the CDN host is blocked.
Common situations: Daemon paused (e.g. on queue/backpressure) long enough that the signed CDN URL expired; Leonardo CDN maintenance (5xx); firewall blocking the image CDN host; transient CDN 503/504.
Related errors
- grok video fetch ${dlResp.status}
- openrouter video download ${dlResp.status}
- leonardo.ai submit ${submitResp.status}: ${truncate(submitTe
- leonardo.ai poll ${pollResp.status}
- download ${url} failed: ${resp.status} ${resp.statusText}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/a9aeb9032395e47a.
Report an issue: GitHub.