FoundationAgents/MetaGPT · error · Exception
Failed to parse {rsp}
Error message
Failed to parse
{rsp}
What it means
The terminal else-branch in the tool-call response parser: the message has tool_calls present but no usable first tool call, AND content is None (or tool_calls is non-None with content None), so none of the recognized branches match. MetaGPT logs the full response and raises a generic Exception with 'Failed to parse', meaning the ChatCompletion shape was unexpected.
Source
Thrown at metagpt/provider/openai_api.py:263
return json.loads(message.tool_calls[0].function.arguments, strict=False)
except json.decoder.JSONDecodeError as e:
error_msg = (
f"Got JSONDecodeError for \n{'--'*40} \n{message.tool_calls[0].function.arguments}, {str(e)}"
)
logger.error(error_msg)
return self._parse_arguments(message.tool_calls[0].function.arguments)
elif message.tool_calls is None and message.content is not None:
# reponse is code, fix openai tools_call respond bug,
# The response content is `code``, but it appears in the content instead of the arguments.
code_formats = "```"
if message.content.startswith(code_formats) and message.content.endswith(code_formats):
code = CodeParser.parse_code(text=message.content)
return {"language": "python", "code": code}
# reponse is message
return {"language": "markdown", "code": self.get_choice_text(rsp)}
else:
logger.error(f"Failed to parse \n {rsp}\n")
raise Exception(f"Failed to parse \n {rsp}\n")
def get_choice_text(self, rsp: ChatCompletion) -> str:
"""Required to provide the first text of choice"""
return rsp.choices[0].message.content if rsp.choices else ""
def _calc_usage(self, messages: list[dict], rsp: str) -> CompletionUsage:
usage = CompletionUsage(prompt_tokens=0, completion_tokens=0, total_tokens=0)
if not self.config.calc_usage:
return usage
try:
usage.prompt_tokens = count_message_tokens(messages, self.pricing_plan)
usage.completion_tokens = count_output_tokens(rsp, self.pricing_plan)
except Exception as e:
logger.warning(f"usage calculation failed: {e}")
return usage
View on GitHub (pinned to 11cdf466d0)
Solutions
- Check rsp.choices[0].finish_reason; if 'length', raise max tokens and retry.
- Retry the call — transient malformed completions often resolve on resampling.
- If the backend is an OpenAI-compatible proxy, verify it faithfully nulls (not empties) tool_calls when unused.
- Guard before parsing: fall back to text handling when message.content is None and not message.tool_calls.
Example fix
# before
msg = rsp.choices[0].message
if msg.tool_calls: # empty list [] is truthy-checked incorrectly upstream
...
# after
msg = rsp.choices[0].message
if msg.content is None and not msg.tool_calls:
raise RuntimeError(f"empty completion, finish_reason={rsp.choices[0].finish_reason}") Defensive patterns
Strategy: try-catch
Validate before calling
msg = rsp.choices[0].message if rsp.choices else None
if msg is None or (msg.content is None and not msg.tool_calls):
finish = rsp.choices[0].finish_reason if rsp.choices else None
raise RuntimeError(f"unparseable completion, finish_reason={finish}") Try / catch
try:
result = provider.get_choice_function_arguments(rsp)
except Exception as e:
if "Failed to parse" in str(e):
rsp = provider.completion(messages) # resample once
result = provider.get_choice_function_arguments(rsp)
else:
raise Prevention
- Check finish_reason for 'length' before parsing tool calls
- Resample once on malformed completions before failing hard
- Validate OpenAI-compatible proxies null tool_calls instead of returning []
When it happens
Trigger: get_choice_function_arguments on a response where message.tool_calls is an empty list (not None) while message.content is None, or tool_calls exists but tool_calls[0].function.arguments is missing; also finish_reason='length' responses truncated before any content or call.
Common situations: Truncated responses (max tokens hit during tool-call emission), provider quirks returning empty tool_calls arrays, or non-OpenAI backends whose message objects behave differently around None vs empty.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Parse code error for {arguments}
- Cannot find the answer phrase "{response}"
- Could not find content between [{tag}] and [/{tag}]
- Unterminated string starting at
- Missing fields: {missing_fields}
AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14).
Data as JSON: /api/errors/940847bf56ab8d0f.
Report an issue: GitHub.