nexu-io/open-design · error · Error

openrouter image download ${imgResp.status}

Error message

openrouter image download ${imgResp.status}

What it means

Thrown when OpenRouter returned an image as a hosted http(s) URL (rather than an inline base64 data URL) and the secondary fetch of that URL returned non-2xx. The code branches on a `data:image/...;base64,` regex first; only if the URL starts with 'http' does it fetch — so this fires only on the hosted-URL delivery path.

Source

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

  }

  const dataUrl: string | undefined = images[0]?.image_url?.url;
  if (!dataUrl) {
    throw new Error(
      `openrouter image response missing image_url.url: ${truncate(text, 200)}`,
    );
  }

  // Strip the data URL prefix (e.g. "data:image/png;base64,") and
  // decode the remaining base64 payload.
  const b64Match = dataUrl.match(/^data:image\/[^;]+;base64,(.+)$/s);
  let bytes: Buffer;
  if (b64Match) {
    bytes = Buffer.from(b64Match[1]!, 'base64');
  } else if (dataUrl.startsWith('http')) {
    // Some models may return a plain URL instead of inline base64.
    const imgResp = await fetch(dataUrl, withMediaRequestInit(ctx));
    if (!imgResp.ok) throw new Error(`openrouter image download ${imgResp.status}`);
    bytes = Buffer.from(await imgResp.arrayBuffer());
  } else {
    // Assume raw base64 without prefix.
    bytes = Buffer.from(dataUrl, 'base64');
  }

  return {
    bytes,
    providerNote: `openrouter/${wireModel} · ${aspectRatio} · ${bytes.length} bytes`,
    suggestedExt: sniffImageExt(bytes),
  };
}

// ---------------------------------------------------------------------------
// OpenRouter's video API is a normalised, asynchronous interface sitting
// in front of multiple upstream providers (ByteDance Seedance 2.0,
// Google Veo 3.1, Alibaba Wan 2.7, etc.). The workflow mirrors the
// Grok / Volcengine pattern used elsewhere in this file:

View on GitHub (pinned to 5be4028344)

Solutions

  1. Retry the render — hosted-URL expiry is the most common cause.
  2. If reproducible, attach the same authorization/attribution headers to the secondary fetch (currently withMediaRequestInit(ctx) carries ctx-level options).
  3. Check OpenRouter status for CDN incidents when the status is 5xx.
  4. Where possible prefer models/config that return inline base64 to avoid the secondary fetch entirely.

Example fix

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

// after — one retry on 5xx with clearer status
let imgResp = await fetch(dataUrl, withMediaRequestInit(ctx));
if (!imgResp.ok && imgResp.status >= 500) {
  await sleep(1000);
  imgResp = await fetch(dataUrl, withMediaRequestInit(ctx));
}
if (!imgResp.ok) {
  throw new Error(`openrouter image download ${imgResp.status} from ${truncate(dataUrl, 80)}`);
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate the hosted URL shape and freshness before fetching
function isOpenRouterImageUrl(u: unknown): u is string {
  return typeof u === 'string' && /^https?:\/\//.test(u) && u.length < 8192;
}

Type guard

function isRetryableDownloadStatus(status: number): boolean {
  return status === 429 || status >= 500;
}

Try / catch

let bytes: Buffer | undefined;
for (let attempt = 0; attempt < 2; attempt++) {
  const r = await fetch(dataUrl, withMediaRequestInit(ctx));
  if (r.ok) { bytes = Buffer.from(await r.arrayBuffer()); break; }
  if (attempt === 0 && isRetryableDownloadStatus(r.status)) { await sleep(1000); continue; }
  throw new Error(`openrouter image download ${r.status}`);
}

Prevention

When it happens

Trigger: The hosted image URL expired before download, the CDN returned 403/404 because no referer/auth was attached, the host had a transient 5xx, or the URL is behind a rate-limited gateway.

Common situations: Slow networks where the signed URL TTL lapses, OpenRouter image-CDN incidents, or corporate proxies stripping required headers off the secondary fetch.

Related errors


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