nexu-io/open-design · error · Error
aihubmix gemini image response had no inline image data: ${J
Error message
aihubmix gemini image response had no inline image data: ${JSON.stringify(data).slice(0, 200)} What it means
Plain Error thrown by aihubmixGeminiImageBytes when the HTTP response was OK (2xx) but the parsed JSON contains no inline image data — specifically, none of the candidate parts contain inlineData.data / inline_data.data as a non-empty string. The error echoes the first 200 chars of the JSON for debugging. This indicates the model accepted the request but returned text-only or empty content instead of an image.
Source
Thrown at apps/daemon/src/integrations/aihubmix.ts:153
body: JSON.stringify({
contents: [{ role: 'user', parts: [{ text: req.prompt }] }],
generationConfig: {
responseModalities: ['TEXT', 'IMAGE'],
imageConfig: { aspectRatio: req.aspect },
},
}),
});
if (!resp.ok) {
const text = await resp.text().catch(() => '');
throw new Error(`aihubmix image (gemini) ${resp.status}: ${text.slice(0, 240)}`);
}
const data = (await resp.json()) as any;
const parts: any[] = data?.candidates?.[0]?.content?.parts ?? [];
const b64 = parts
.map((p) => p?.inlineData?.data || p?.inline_data?.data)
.find((d) => typeof d === 'string' && d);
if (!b64) {
throw new Error(
`aihubmix gemini image response had no inline image data: ${JSON.stringify(data).slice(0, 200)}`,
);
}
return Buffer.from(b64, 'base64');
}
// Catalogue ids vs wire names. The media registry requires globally-unique
// model ids, but `gpt-image-1` / `dall-e-3` / `tts-1` are already owned by the
// `openai` provider. So AIHubMix's models are registered with an `aihubmix-`
// prefix and mapped back to the real upstream name here. A plain prefix strip
// is the fallback so adding a new `aihubmix-<wire>` entry needs no edit here.
const AIHUBMIX_WIRE_MODELS: Record<string, string> = {
'aihubmix-gpt-image-1': 'gpt-image-1',
'aihubmix-dall-e-3': 'dall-e-3',
'aihubmix-tts-1': 'tts-1',
};
export function aihubmixWireModel(catalogId: string): string {View on GitHub (pinned to 5be4028344)
Solutions
- Inspect the interpolated JSON (first 200 chars) — a safety refusal is usually visible as text content.
- Rephrase the prompt to avoid flagged content; try a different aspectRatio.
- Confirm the wireModel actually supports image output (some gemini variants are text-only).
- Verify generationConfig.responseModalities includes IMAGE and the model honors it.
- If the JSON shape looks valid but image data is under a different key, the parser may need updating — file an issue with the response shape.
Defensive patterns
Strategy: validation
Validate before calling
function hasInlineImage(data: unknown): boolean {
const parts = (data as any)?.candidates?.[0]?.content?.parts ?? [];
return parts.some((p: any) =>
typeof (p?.inlineData?.data ?? p?.inline_data?.data) === 'string'
&& (p.inlineData?.data ?? p.inline_data?.data).length > 0);
} Try / catch
try {
return await aihubmixGeminiImageBytes(req, doFetch);
} catch (err) {
if (err instanceof Error && /no inline image data/.test(err.message)) {
// 200 but text-only response — usually a safety refusal or wrong model
throw new ImageGenerationRefusedError('Model returned no image (possible safety filter or text-only model)');
}
throw err;
} Prevention
- Rephrase prompts that trip Gemini safety filters.
- Verify the wireModel supports image output (some gemini variants are text-only).
- Confirm responseModalities includes IMAGE on the upstream config.
- Inspect the echoed JSON (first 200 chars) to distinguish refusal from schema drift.
When it happens
Trigger: The gemini/imagen model returned 200 with only text parts (e.g. a safety refusal, a 'cannot generate' message, or a text explanation); responseModalities did not include IMAGE on the upstream side; the model safety filter blocked the prompt and returned text instead; AIHubMix stripped the image data; an unexpected response schema variant where image data lives under a different key.
Common situations: Prompt tripped Gemini's safety filters (returns text refusal with 200); model is text-only despite being routed here; aspectRatio/prompt combination the model declined; AIHubMix passed through a text-only response from an upstream error; a model that requires a different image-output configuration.
Related errors
- aihubmix image (gemini) ${resp.status}: ${text.slice(0, 240)
- no Nano Banana API key — configure it in Settings or set OD_
- nano-banana image ${resp.status}: ${truncate(text, 240)}
- nano-banana image non-JSON: ${truncate(text, 200)}
- nano-banana image response missing candidates[].content.part
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/7db8cfa5b81922fa.
Report an issue: GitHub.