invoke-ai/InvokeAI · error · ExternalProviderRequestError
Gemini response payload missing candidates
Error message
Gemini response payload missing candidates
What it means
ExternalProviderRequestError raised when the parsed Gemini JSON object has no 'candidates' key or its value is not a list. A successful generateContent response must contain a candidates array; its absence means the request was rejected at the model level (e.g. safety blocking with only promptFeedback present) or the response shape is wrong. The provider cannot extract any images without candidates.
Source
Thrown at invokeai/app/services/external_generation/providers/gemini.py:132
if response.status_code == 429:
retry_after = _parse_retry_after(response.headers.get("retry-after"))
raise ExternalProviderRateLimitError(
f"Gemini rate limit exceeded. {f'Retry after {retry_after:.0f}s.' if retry_after else 'Please try again later.'}",
retry_after=retry_after,
)
raise ExternalProviderRequestError(
f"Gemini request failed with status {response.status_code} for model '{model_id}': {response.text}"
)
data = response.json()
if not isinstance(data, dict):
raise ExternalProviderRequestError("Gemini response payload was not a JSON object")
images: list[ExternalGeneratedImage] = []
text_parts: list[str] = []
finish_messages: list[str] = []
candidates = data.get("candidates")
if not isinstance(candidates, list):
raise ExternalProviderRequestError("Gemini response payload missing candidates")
for candidate in candidates:
if not isinstance(candidate, dict):
continue
finish_message = candidate.get("finishMessage")
finish_reason = candidate.get("finishReason")
if isinstance(finish_message, str):
finish_messages.append(finish_message)
elif isinstance(finish_reason, str):
finish_messages.append(f"Finish reason: {finish_reason}")
for part in _iter_response_parts(candidate):
inline_data = part.get("inline_data") or part.get("inlineData")
if isinstance(inline_data, dict):
encoded = inline_data.get("data")
if encoded:
image = decode_image_base64(encoded)
images.append(ExternalGeneratedImage(image=image, seed=request.seed))
continue
file_data = part.get("fileData") or part.get("file_data")View on GitHub (pinned to 0b6a024f2f)
Solutions
- Inspect the full response logged by the provider (it logs data on the no-images path) — look for promptFeedback.blockReason.
- Rephrase the prompt to avoid content that triggers safety filters; remove problematic reference images.
- Verify the API key has access to the requested Gemini image model and billing is enabled.
- If a proxy is in play, bypass it or fix its passthrough of the Gemini response.
Example fix
// before: prompt likely to be blocked prompt = "...violent/NSFW wording..." // after: sanitised prompt less likely to be safety-blocked prompt = sanitize(prompt) # strip flagged terms result = provider.generate(request)
Defensive patterns
Strategy: type-guard
Type guard
def has_candidates(data: object) -> bool:
return isinstance(data, dict) and isinstance(data.get("candidates"), list) and bool(data["candidates"])
# a blocked prompt yields {"promptFeedback": {"blockReason": ...}} with no candidates Try / catch
try:
result = provider.generate(request)
except ExternalProviderRequestError as e:
if "missing candidates" in str(e):
notify_user("Prompt or images were likely blocked by Gemini safety filters; rephrase and retry.")
else:
raise Prevention
- Pre-screen prompts and reference images for content likely to trip safety filters.
- Treat missing candidates as a safety/permission signal, not a transient failure — don't blind-retry.
- Ensure the API key has access (and billing) for the requested image model.
- Log the full response (as the provider does) to read promptFeedback.blockReason.
When it happens
Trigger: data.get('candidates') is missing or not a list despite HTTP 200 — typically when Google returns {"promptFeedback": {"blockReason": "SAFETY"}} for a blocked prompt, an empty object from a broken proxy, or a MODEL_NOT_FOUND-style JSON error body returned with a 200 status by a gateway.
Common situations: Prompt (or init/reference images) tripping Gemini's safety filters; API key lacking access to the requested image model; content-filtered prompts in regions/policies; proxy stripping the real response.
Related errors
- Gemini response contained no images.{detail}
- Gemini response payload was not a JSON object
- Gemini returned fileUri instead of inline image data: {file_
- DashScope response contained no images: {data}
- DashScope async response contained no images: {output}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/affcf916737e5bbe.
Report an issue: GitHub.