PrefectHQ/fastmcp · error · ValueError

No content in response from completion

Error message

No content in response from completion

What it means

The completion had at least one choice, but the first choice's message has no text content (empty string or None). Since the plain sampling result path only supports text output, the handler raises this ValueError instead of returning an empty CreateMessageResult.

Source

Thrown at fastmcp_slim/fastmcp/client/sampling/handlers/openai.py:403

        return openai_messages

    @staticmethod
    def _chat_completion_to_create_message_result(
        chat_completion: ChatCompletion,
    ) -> CreateMessageResult:
        if len(chat_completion.choices) == 0:
            raise ValueError("No response for completion")

        first_choice = chat_completion.choices[0]

        if content := first_choice.message.content:
            return CreateMessageResult(
                content=TextContent(type="text", text=content),
                role="assistant",
                model=chat_completion.model,
            )

        raise ValueError("No content in response from completion")

    def _select_model_from_preferences(
        self, model_preferences: ModelPreferences | str | list[str] | None
    ) -> ChatModel:
        for model_option in self._iter_models_from_preferences(model_preferences):
            if model_option in get_args(ChatModel):
                chosen_model: ChatModel = model_option  # type: ignore[assignment]  # ty:ignore[invalid-assignment]
                return chosen_model

        return self.default_model

    @staticmethod
    def _convert_tools_to_openai(tools: list[Tool]) -> list[ChatCompletionToolParam]:
        """Convert MCP tools to OpenAI tool format."""
        openai_tools: list[ChatCompletionToolParam] = []
        for tool in tools:
            # Build parameters dict, ensuring required fields
            parameters: dict[str, Any] = dict(tool.input_schema)

View on GitHub (pinned to 1f02114297)

Solutions

  1. Increase max_tokens in the sampling params so the model can emit text.
  2. Check finish_reason on the choice — 'content_filter' or 'length' indicates truncation/blocking, not a model bug.
  3. If tool calls are expected, use the tools-capable result path instead of the plain one.
  4. Catch the ValueError and retry with adjusted parameters or fall back to another provider.

Example fix

// before
params = CreateMessageRequestParams(messages=messages, maxTokens=1)
// after
params = CreateMessageRequestParams(messages=messages, maxTokens=1024)
Defensive patterns

Strategy: validation

Validate before calling

def assert_completion_has_text(completion):
    if not completion.choices:
        raise ValueError('No choices')
    if not completion.choices[0].message.content:
        raise ValueError('First choice has no text; check finish_reason/max_tokens')

Type guard

def has_text_content(completion) -> bool:
    return bool(completion.choices and completion.choices[0].message.content)

Try / catch

try:
    result = await sampling_handler(messages, params)
except ValueError as e:
    if str(e) == 'No content in response from completion':
        params.maxTokens = max(params.maxTokens or 0, 1024)
        result = await sampling_handler(messages, params)
    else:
        raise

Prevention

When it happens

Trigger: A ChatCompletion whose first choice's message.content is '' or None reaches _chat_completion_to_create_message_result — e.g. the model finished without emitting text (abnormal stop, length exhaustion before any tokens, or refusal producing empty content).

Common situations: max_tokens set so low the model emits nothing; content filter stripping the message body; model returning only tool calls while using the plain (no-tools) sampling path; deprecated or broken model returning empty bodies.

Related errors


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