BerriAI/litellm · error · ValueError
{model} unable to complete request: {raw_response.incomplete
Error message
{model} unable to complete request: {raw_response.incomplete_details.reason} What it means
After converting the Responses API output to chat choices, zero choices were produced and raw_response.incomplete_details.reason is set. The provider is telling you it stopped early — e.g. max_output_tokens reached or a content filter fired — so the output contained no convertible message items.
Source
Thrown at litellm/completion_extras/litellm_responses_transformation/transformation.py:766
if len(output_items) == 0:
recovered_output_items: Final = self._recover_output_items_from_logging(logging_obj)
if recovered_output_items:
output_items = cast(Any, recovered_output_items)
raw_response.output = cast(Any, recovered_output_items)
verbose_logger.warning(
"Recovered empty Responses API output from raw SSE for model=%s",
model,
)
# Convert response output to choices using the static helper
choices: Final = self._convert_response_output_to_choices(
output_items=output_items,
handle_raw_dict_callback=self._handle_raw_dict_response_item,
)
if len(choices) == 0:
if raw_response.incomplete_details is not None and raw_response.incomplete_details.reason is not None:
raise ValueError(f"{model} unable to complete request: {raw_response.incomplete_details.reason}")
else:
raise ValueError(f"Unknown items in responses API response: {output_items}")
setattr(model_response, "choices", choices)
model_response.model = model
setattr(
model_response,
"usage",
ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage(raw_response.usage),
)
# Preserve hidden params from the ResponsesAPIResponse, especially the headers
# which contain important provider information like x-request-id
raw_response_hidden_params: Final = getattr(raw_response, "_hidden_params", {})
if raw_response_hidden_params:
if not hasattr(model_response, "_hidden_params") or model_response._hidden_params is None:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Raise or remove max_output_tokens so the model has budget to produce message output
- Inspect raw_response.incomplete_details.reason — 'max_output_tokens' means raise the cap; filter reasons mean adjust content
- For reasoning models, budget for reasoning tokens explicitly
Example fix
# before resp = litellm.completion(model="o3", messages=msgs, max_tokens=32) # after — give the model room for reasoning + message output resp = litellm.completion(model="o3", messages=msgs, max_tokens=4096)
Defensive patterns
Strategy: validation
Validate before calling
def check_token_headroom(max_tokens: int | None, max_output_tokens: int | None) -> bool:
cap = max_output_tokens or max_tokens
return cap is None or cap >= 1024 # leave room for reasoning + message Try / catch
try:
resp = litellm.completion(model=m, messages=msgs, max_tokens=cap)
except ValueError as e:
if "unable to complete request" in str(e) and "max_output_tokens" in str(e):
resp = litellm.completion(model=m, messages=msgs, max_tokens=cap * 4)
else:
raise Prevention
- Set max_tokens generously for reasoning models
- Check incomplete_details.reason in responses before bridging
- Watch finish_reason/usage in callbacks to catch truncation early
When it happens
Trigger: Calling with max_output_tokens set so low the model never emits a message item; safety-system refusal truncation; providers that stop before any output when filters trigger.
Common situations: Aggressive max_tokens limits in agent loops; content-moderation systems; long reasoning models spending the entire token budget on reasoning items.
Related errors
- tool call not supported: {tool_call}
- Unexpected response type: {type(raw_response)}
- Unknown items in responses API response: {output_items}
- Keyword banned. Keyword={word}
- Violated content safety policy. Category={category}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/69cca969a5db8c00.
Report an issue: GitHub.