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

  1. Check rsp.choices[0].finish_reason; if 'length', raise max tokens and retry.
  2. Retry the call — transient malformed completions often resolve on resampling.
  3. If the backend is an OpenAI-compatible proxy, verify it faithfully nulls (not empties) tool_calls when unused.
  4. 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

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

Related errors


AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14). Data as JSON: /api/errors/940847bf56ab8d0f. Report an issue: GitHub.