BerriAI/litellm · error · ValueError
Chat provider: Invalid function argument delta
Error message
Chat provider: Invalid function argument delta {parsed_chunk} What it means
A Responses API streaming event of type response.function_call_arguments.delta or response.custom_tool_call_input.delta arrived without a usable 'delta' payload — the field is missing, None, or an empty string. Since the delta text is the only content of these events, the translator cannot produce a tool-call argument fragment and raises with the full chunk echoed. It almost always indicates a provider/gateway emitting non-conforming delta events.
Solutions
- Upgrade litellm — argument-delta handling has been made more tolerant across releases
- Capture the raw event from the error text and report the non-conforming provider/gateway
- If you control the event source, always include 'delta' (empty string events should simply not be sent)
- Wrap custom translation loops to skip delta events where event.get('delta') is falsy
Example fix
// before
out = translate_responses_chunk_to_openai_stream(event) # event has no 'delta' key -> ValueError: Chat provider: Invalid function argument delta
// after
if event.get("type") in ("response.function_call_arguments.delta",
"response.custom_tool_call_input.delta") and not event.get("delta"):
continue # skip non-conforming empty delta events
out = translate_responses_chunk_to_openai_stream(event) Defensive patterns
Strategy: fallback
Validate before calling
DELTA_EVENTS = ("response.function_call_arguments.delta",
"response.custom_tool_call_input_delta")
def delta_event_is_translatable(chunk: dict) -> bool:
if chunk.get("type") in DELTA_EVENTS and not chunk.get("delta"):
return False # non-conforming event without payload: skip it
return True Type guard
def has_delta_payload(chunk: dict) -> bool:
return bool(chunk.get("delta")) or chunk.get("type") not in ("response.function_call_arguments.delta", "response.custom_tool_call_input_delta") Try / catch
try:
out = translate_responses_chunk_to_openai_stream(chunk)
except ValueError as e:
if "Invalid function argument delta" in str(e):
logger.debug("skipping delta event without payload: %s", chunk)
out = None # skip and continue the stream; argument fragments arrive in other events
else:
raise Prevention
- Skip delta-class events whose 'delta' field is missing or empty instead of aborting the whole stream
- Capture offending raw events for the bug report — the provider/gateway is non-conforming
- Upgrade litellm, where tolerance for empty argument deltas improves across releases
When it happens
Trigger: A provider streaming function-call argument deltas that omits the delta field on some events (seen with nonstandard OpenAI-compatible gateways); a final flush event with empty delta; middleware rewriting events and dropping the delta key; fabricated test streams missing the field.
Common situations: Third-party gateways in front of Responses-API models with imperfect SSE fidelity; tool-calling agents streaming through the bridge; versions of litellm before empty-delta tolerance was added; recording/replay fixtures that lost fields.
Related errors
- Chat provider: Empty parsed_chunk
- Chat provider: Invalid chunk type
- Chunk cannot be parsed as CohereStreamChunk
- Error parsing chunk: , Received chunk
- Failed to decode JSON from chunk
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/454d8a5eeb9f9a5a.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/completion_extras/litellm_responses_transformation/transformation.py:1317
choices=[
StreamingChoices(
index=0,
delta=Delta(
tool_calls=[
ChatCompletionToolCallChunk(
id=None,
index=tool_call_index,
type="function",
function=ChatCompletionToolCallFunctionChunk(name=None, arguments=content_part),
)
]
),
finish_reason=None,
)
]
)
else:
raise ValueError(f"Chat provider: Invalid function argument delta {parsed_chunk}")
elif event_type == ResponsesAPIStreamEvents.OUTPUT_ITEM_DONE:
# New output item added
output_item = parsed_chunk.get("item", {})
if output_item.get("type") in ("function_call", "custom_tool_call"):
if tool_call_index_map is None:
# Stateless callers (the responses guardrail handler extracting
# tool calls from a buffered output_item.done) get the complete
# tool call; per-stream callers already received it via
# output_item.added and the argument delta events
return ModelResponseStream(
choices=[ # mutable-ok: ModelResponseStream coerces only list choices
StreamingChoices(
index=0,
delta=Delta(
tool_calls=(
_tool_call_dict_from_output_item(
output_item, parsed_chunk.get("output_index", 0)
),View on GitHub (pinned to 77b7c6c40c)