invoke-ai/InvokeAI · error · ExternalProviderRequestError
Gemini response contained no images.{detail}
Error message
Gemini response contained no images.{detail} What it means
ExternalProviderRequestError raised after the provider parsed all candidates and found zero decodable inline images. The message is enriched with a detail suffix: finish messages/finish reasons from candidates (e.g. 'Finish reason: SAFETY') or, if none, the model's text parts (truncated to 500 chars), so the developer can see why Gemini produced text-only or empty output despite a 200 response.
Source
Thrown at invokeai/app/services/external_generation/providers/gemini.py:172
raise ExternalProviderRequestError(
f"Gemini returned fileUri instead of inline image data: {file_uri}"
)
text = part.get("text")
if isinstance(text, str):
text_parts.append(text)
if not images:
self._logger.error("Gemini response contained no images: %s", data)
detail = ""
if finish_messages:
combined = " ".join(message.strip() for message in finish_messages if message.strip())
if combined:
detail = f" Response status: {combined[:500]}"
elif text_parts:
combined = " ".join(text_parts).strip()
if combined:
detail = f" Response text: {combined[:500]}"
raise ExternalProviderRequestError(f"Gemini response contained no images.{detail}")
return ExternalGenerationResult(
images=images,
seed_used=request.seed,
provider_metadata={"model": request.model.provider_model_id},
)
def _iter_response_parts(candidate: dict[str, object]) -> list[dict[str, object]]:
content = candidate.get("content")
if isinstance(content, dict):
content_parts = content.get("parts")
if isinstance(content_parts, list):
return [part for part in content_parts if isinstance(part, dict)]
contents = candidate.get("contents")
if isinstance(contents, list):
parts: list[dict[str, object]] = []
for item in contents:View on GitHub (pinned to 0b6a024f2f)
Solutions
- Read the 'Response status'/'Response text' suffix in the message — it names the finish reason or the model's textual excuse.
- If SAFETY: rephrase the prompt or remove flagged reference/init images.
- If text-only: strengthen the instruction to request an image (the provider's system instruction already tries this) and avoid prompts that read as questions.
- Retry — transient model degradation often resolves on a second attempt.
- Try a different Gemini image model id for the workload.
Example fix
// before: retrying blindly on empty output
for _ in range(3):
try:
return provider.generate(request)
except ExternalProviderRequestError:
pass
// after: inspect finish reason and rephrase once if safety/text-only
try:
return provider.generate(request)
except ExternalProviderRequestError as e:
if "SAFETY" in str(e):
request = replace_prompt(request, sanitized_prompt)
return provider.generate(request)
raise Defensive patterns
Strategy: try-catch
Try / catch
try:
result = provider.generate(request)
except ExternalProviderRequestError as e:
detail = str(e)
if "SAFETY" in detail or "RECITATION" in detail:
notify_user("Gemini blocked this request; rephrase the prompt.")
elif "Response text:" in detail:
retry_once_with_stronger_image_instruction(request) # model answered in prose
else:
retry_once(request) # transient empty response Prevention
- Parse the detail suffix — it tells you whether to rephrase (safety/text) or just retry (transient).
- Write prompts that clearly request an image, not questions or explanations.
- Prefer init/reference images that are policy-compliant to avoid finishReason SAFETY.
- Cap retries at 1-2 to avoid burning quota on prompts the model will never fulfill.
When it happens
Trigger: All candidates contained only text parts (model answered with prose instead of an image), parts were skipped as non-dict, inline_data.data was empty, or candidates carried finishReason like SAFETY/RECITATION with no image payload.
Common situations: Prompt interpreted as a question rather than an image request; safety-filtered content with finishReason SAFETY; model overload returning degraded text-only answers; prompt asking for text output explicitly; invalid imageConfig causing silent fallback.
Related errors
- Gemini response payload missing candidates
- DashScope response contained no images: {data}
- DashScope async response contained no images: {output}
- Gemini API key is not configured
- Gemini rate limit exceeded. {f'Retry after {retry_after:.0f}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/e1099a942e00c61d.
Report an issue: GitHub.