{"record":{"id":"4d9f28c4aeddd47f","repo":"microsoft/autogen","slug":"expected-a-single-json-object-but-found-len-json","errorCode":null,"errorMessage":"Expected a single JSON object, but found {len(json_objs)}","messagePattern":"Expected a single JSON object, but found (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/models/anthropic/_anthropic_client.py","lineNumber":252,"sourceCode":"    return __empty_content_to_whitespace(message.content)\n\n\ndef assistant_message_to_anthropic(message: AssistantMessage) -> MessageParam:\n    assert_valid_name(message.source)\n\n    if isinstance(message.content, list):\n        # Tool calls\n        tool_use_blocks: List[ToolUseBlock] = []\n\n        for func_call in message.content:\n            # Parse the arguments and convert to dict if it's a JSON string\n            args = func_call.arguments\n            args = __empty_content_to_whitespace(args)\n            if isinstance(args, str):\n                try:\n                    json_objs = extract_json_from_str(args)\n                    if len(json_objs) != 1:\n                        raise ValueError(f\"Expected a single JSON object, but found {len(json_objs)}\")\n                    args_dict = json_objs[0]\n                except json.JSONDecodeError:\n                    args_dict = {\"text\": args}\n            else:\n                args_dict = args\n\n            tool_use_blocks.append(\n                ToolUseBlock(\n                    type=\"tool_use\",\n                    id=func_call.id,\n                    name=func_call.name,\n                    input=args_dict,\n                )\n            )\n\n        # Include thought if available\n        content_blocks: List[ContentBlock] = []\n        if hasattr(message, \"thought\") and message.thought is not None:","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/models/anthropic/_anthropic_client.py#L234-L270","documentation":"When converting a previous AssistantMessage's tool calls back into Anthropic ToolUseBlocks, the client parses each function-call arguments string expecting exactly one JSON object (Anthropic requires tool input as a single object). If extract_json_from_str finds zero or multiple JSON objects in the string, it raises ValueError reporting how many were found. The nearby except json.JSONDecodeError fallback never fires because this ValueError is a different exception type.","triggerScenarios":"Replaying a conversation where a tool call's arguments contain two concatenated JSON objects (e.g. '{\"a\":1}{\"b\":2}'), an empty/whitespace string after coercion, or text with no complete JSON; function-calling models that emit malformed argument strings.","commonSituations":"Multi-turn agents feeding history back through the Anthropic client after a different model produced sloppy tool args; hand-built histories with copy-paste concatenation; truncation mid-JSON leaving zero parseable objects.","solutions":["Sanitize stored tool-call arguments to a single JSON object before replaying history (validate with json.loads and re-dump).","When constructing FunctionCall objects yourself, always pass json.dumps({...}) as arguments, never concatenated objects.","If a legacy call's args are unrecoverable, replace with {} and a note, or drop that turn from the context."],"exampleFix":"# before\nFunctionCall(id='1', name='run', arguments='{\"a\":1}{\"b\":2}')  # ValueError on replay\n\n# after\nimport json\nFunctionCall(id='1', name='run', arguments=json.dumps({\"a\": 1, \"b\": 2}))","handlingStrategy":"validation","validationCode":"import json\n\ndef safe_args(args) -> str:\n    if isinstance(args, str):\n        try:\n            obj = json.loads(args)\n            if isinstance(obj, dict):\n                return args\n        except json.JSONDecodeError:\n            pass\n        return json.dumps({'text': args})\n    return json.dumps(args)","typeGuard":"def is_single_json_object(args: str) -> bool:\n    try:\n        return isinstance(json.loads(args), dict)\n    except (json.JSONDecodeError, TypeError):\n        return False","tryCatchPattern":"try:\n    res = await client.create(history)\nexcept ValueError as e:\n    if 'single JSON object' in str(e):\n        history = [sanitize_function_calls(m) for m in history]\n        res = await client.create(history)\n    else:\n        raise","preventionTips":["Always create FunctionCall arguments via json.dumps of one dict","Validate stored tool-call args on load from persistence","Never concatenate JSON objects into a single arguments string"],"tags":["anthropic","tool-calls","json","conversation-history"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}