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
- Confirm wireModel is listed at openrouter.ai/models as supporting image output (the `["image","text"]` modality).
- Inspect choices[0].message.content — a textual refusal explains the empty image array.
- Rephrase the prompt and retry.
- 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
- Validate the chosen slug is image-capable in the OpenRouter catalogue before dispatch.
- When the images array is empty, inspect choices[0].message.content for a refusal explanation.
- Reword prompts that trigger refusals instead of retrying unchanged.
- Track which models return empty arrays most often and warn users at selection time.
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
- grok image response missing b64_json/url
- nano-banana image response missing candidates[].content.part
- openrouter image non-JSON response: ${truncate(text, 200)}
- openrouter image response missing image_url.url: ${truncate(
- grok image response had no data[0]
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/cb4d07e76c9925b8.
Report an issue: GitHub.