PrefectHQ/fastmcp · error · ValueError

Model returned only thinking/reasoning content with no respo

Error message

Model returned only thinking/reasoning content with no response text. / No content in response (finish_reason={candidate.finish_reason})

What it means

On the non-tool sampling path, the response candidate had no usable text content. The error distinguishes two cases: the model emitted only 'thought' (reasoning) parts, or the response contained no content at all (with the finish_reason reported). Raised because a CreateMessageResult requires text content.

Source

Thrown at fastmcp_slim/fastmcp/client/sampling/handlers/google_genai.py:341

    response: GenerateContentResponse,
    model: str,
) -> CreateMessageResult:
    """Convert Google GenAI response to CreateMessageResult (no tools)."""
    if not (text := response.text):
        candidate = _get_candidate_from_response(response)
        # Check if the response only contained thinking
        has_thoughts = (
            candidate.content
            and candidate.content.parts
            and all(getattr(p, "thought", False) for p in candidate.content.parts)
        )
        if has_thoughts:
            msg = (
                "Model returned only thinking/reasoning content with no response text."
            )
        else:
            msg = f"No content in response (finish_reason={candidate.finish_reason})"
        raise ValueError(msg)

    return CreateMessageResult(
        content=TextContent(type="text", text=text),
        role="assistant",
        model=model,
    )


def _response_to_result_with_tools(
    response: GenerateContentResponse,
    model: str,
) -> CreateMessageResultWithTools:
    """Convert Google GenAI response to CreateMessageResultWithTools."""
    candidate = _get_candidate_from_response(response)

    # Determine stop reason and check for function calls
    stop_reason: StopReason
    finish_reason = candidate.finish_reason

View on GitHub (pinned to 1f02114297)

Solutions

  1. Disable or reduce thinking/reasoning config (thinking_config with thinking_budget) so the model produces a final text answer.
  2. Check candidate.finish_reason and adjust the prompt or safety settings accordingly.
  3. Increase max_tokens if generation was truncated before text was emitted.
  4. Catch the ValueError and retry or fall back to another sampling handler.

Example fix

// before
GenerateContentConfig(thinking_config=ThinkingConfig(thinking_budget=8192))
// after
GenerateContentConfig(thinking_config=ThinkingConfig(thinking_budget=0))  # or raise max_tokens
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try:
    result = await client.sample(...)
except ValueError as e:
    if 'only thinking' in str(e) or 'No content in response' in str(e):
        result = await client.sample(messages=messages, max_tokens=increased, ...)  # or disable thinking
    else:
        raise

Prevention

When it happens

Trigger: Calling Client.sample() through GoogleGenAIHandler.__call__ when the model returns only thinking/reasoning parts (e.g. a thinking model with thinking enabled and no final answer), or the candidate finished without producing text (finish_reason like SAFETY, RECITATION, or empty).

Common situations: Using thinking-capable Gemini models where reasoning output consumed the whole budget; safety filter stopping generation before any text; max tokens consumed by thoughts; malformed prompt producing no output.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/6d4cdb1ff61a35a5. Report an issue: GitHub.