harry0703/MoneyPrinterTurbo · error · ValueError

[{llm_provider}] returned invalid response content

Error message

[{llm_provider}] returned invalid response content

What it means

Raised in the gemini adapter branch when reading response.text from google-genai raises AttributeError, IndexError, or ValueError. The google.genai SDK raises ValueError ('response.text' when part candidates lack text) when the model returns no usable text — typically because all candidates were blocked by safety filters or came back empty. The original exception is logged as a warning before re-raising.

Source

Thrown at app/services/llm.py:285

                ],
            )

            try:
                # 新版 google-genai 通过统一 Client 暴露模型服务。上下文管理器
                # 会在请求结束后关闭底层 HTTP 连接,避免频繁生成时积累连接资源。
                with genai.Client(
                    api_key=api_key,
                    http_options=http_options,
                ) as client:
                    response = client.models.generate_content(
                        model=model_name,
                        contents=prompt,
                        config=generation_config,
                    )
                generated_text = response.text
            except (AttributeError, IndexError, ValueError) as e:
                logger.warning(f"gemini returned invalid response content: {str(e)}")
                raise ValueError(f"[{llm_provider}] returned invalid response content")

            return _normalize_text_response(generated_text, llm_provider)

        if adapter == "cloudflare_ai_gateway":
            account_id = extra_values["account_id"]
            gateway_id = extra_values["gateway_id"]
            # Cloudflare 当前推荐的 AI Gateway REST API 兼容 OpenAI SDK。
            # Account ID 用于构造统一端点,Gateway ID 通过请求头选择;这里
            # 不再调用 Workers AI 的 /ai/run/{model} 专用接口。
            client = OpenAI(
                api_key=api_key,
                base_url=(
                    f"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1"
                ),
                default_headers={"cf-aig-gateway-id": gateway_id},
            )
            response = client.chat.completions.create(
                model=model_name,

View on GitHub (pinned to 1f9f19c202)

Solutions

  1. Check the logged warning immediately preceding the raise — it contains the underlying SDK error naming the exact cause (safety block vs empty parts)
  2. If safety-related, rephrase the prompt or lower risk settings; inspect response.candidates[0].finish_reason and safety_ratings in a debug run
  3. For MAX_TOKENS/empty-output, raise max_output_tokens or switch model (e.g. gemini-2.x non-thinking variant)
  4. Verify the google-genai package (not legacy google-generativeai) is installed and matches the SDK this code targets
  5. Retry once via the existing retry loop — transient empty responses do occur

Example fix

# before
response = client.models.generate_content(model=model_name, contents=prompt, config=generation_config)
generated_text = response.text  # raises ValueError when candidates blocked

# after
response = client.models.generate_content(model=model_name, contents=prompt, config=generation_config)
if not response.candidates:
    raise ValueError(f"[{llm_provider}] no candidates returned (finish_reason={getattr(response.candidates[0], 'finish_reason', 'n/a') if response.candidates else 'none'})")
generated_text = response.text
Defensive patterns

Strategy: try-catch

Type guard

def gemini_has_text(response) -> bool:
    try:
        return bool(response and response.text and response.text.strip())
    except (AttributeError, ValueError, IndexError):
        return False

Try / catch

except ValueError as e: — the code already narrows to (AttributeError, IndexError, ValueError) around response.text; callers should retry once (transient safety blocks happen) but rephrase the prompt if a specific subject consistently triggers it

Prevention

When it happens

Trigger: client.models.generate_content(...) succeeds HTTP-wise but response.text raises: candidate.finish_reason == SAFETY (prompt blocked), all parts empty (MAX_TOKENS with no output), recitation filter, or response object lacking expected attributes (SDK version mismatch); also prompt rejected by Gemini's content policy.

Common situations: Video script/keyword prompts occasionally tripping Gemini safety filters; old google-generativeai vs new google-genai package confusion; max_output_tokens=2048 with thinking models producing empty text; prompts with sensitive words (violence, medical) in the video subject; regional restrictions returning empty candidates.

Related errors


AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14). Data as JSON: /api/errors/7b78a952cd1900a4. Report an issue: GitHub.