nexu-io/open-design · error · Error

openrouter image response contained no images for model ${wi

Error message

openrouter image response contained no images for model ${wireModel}: ${truncate(text, 200)}

What it means

Thrown by renderOpenRouterImage when the parsed response has no `choices[0].message.images` array (or it is empty). OpenRouter embeds generated images under that non-standard path for multi-modal chat models; an empty/missing array means the model ran but produced no image — usually because the model is text-only, the prompt was refused, or the model returned only text.

Source

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

    signal: AbortSignal.timeout(Math.max(OPENAI_IMAGE_HEADERS_TIMEOUT_MS, OPENAI_IMAGE_BODY_TIMEOUT_MS)),
  }));
  const text = await resp.text();
  if (!resp.ok) {
    throw new Error(`openrouter image ${resp.status}: ${truncate(text, 240)}`);
  }

  let data: any;
  try {
    data = JSON.parse(text);
  } catch {
    throw new Error(`openrouter image non-JSON response: ${truncate(text, 200)}`);
  }

  // Extract the first generated image from the response.
  const images: any[] | undefined =
    data?.choices?.[0]?.message?.images;
  if (!images || images.length === 0) {
    throw new Error(
      `openrouter image response contained no images for model ${wireModel}: `
      + truncate(text, 200),
    );
  }

  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');

View on GitHub (pinned to 5be4028344)

Solutions

  1. Confirm wireModel is listed at openrouter.ai/models as supporting image output (the `["image","text"]` modality).
  2. Inspect choices[0].message.content — a textual refusal explains the empty image array.
  3. Rephrase the prompt and retry.
  4. If OpenRouter moved the field, update the extraction at apps/daemon/src/media/index.ts:1879.

Example fix

// before
if (!images || images.length === 0) {
  throw new Error(`openrouter image response contained no images for model ${wireModel}: ${truncate(text, 200)}`);
}

// after — include any textual refusal reason
const refusal = data?.choices?.[0]?.message?.content;
throw new Error(
  `openrouter image response had no images for ${wireModel}`
  + (refusal ? ` (message: ${truncate(String(refusal), 160)})` : '')
  + `: ${truncate(text, 200)}`,
);
Defensive patterns

Strategy: type-guard

Validate before calling

// Detect textual refusal vs empty image array
function extractOpenRouterImage(data: any, wireModel: string): any[] {
  const images = data?.choices?.[0]?.message?.images;
  if (Array.isArray(images) && images.length > 0) return images;
  const content = data?.choices?.[0]?.message?.content;
  const reason = typeof content === 'string' ? content : JSON.stringify(content ?? '');
  throw new Error(`openrouter image: no images for ${wireModel} (message: ${truncate(reason, 160)})`);
}

Type guard

function isOpenRouterImageArray(v: unknown): v is { image_url: { url: string } }[] {
  return Array.isArray(v) && v.length > 0 && v.every((i: any) => i?.image_url?.url);
}

Try / catch

try {
  const images = extractOpenRouterImage(data, wireModel);
  // ...
} catch (e) {
  if (/no images for/.test(String(e))) { /* surface 'model produced no image' to user */ }
  throw e;
}

Prevention

When it happens

Trigger: wireModel is a text-only chat model mistaken for an image model, the model returned a textual refusal in message.content instead of an image, the underlying provider returned an empty image set, or OpenRouter changed the image embedding path.

Common situations: Selecting a chat model that lacks image output capability, a prompt the underlying provider declined, or an OpenRouter schema revision moving images to a different field.

Related errors


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