{"record":{"id":"b3c02c6842c386e1","repo":"CoplayDev/unity-mcp","slug":"command-at-index-index-must-be-an-object-with-t","errorCode":null,"errorMessage":"Command at index {index} must be an object with 'tool' and 'params' keys","messagePattern":"Command at index (.+?) must be an object with 'tool' and 'params' keys","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Server/src/services/tools/batch_execute.py","lineNumber":103,"sourceCode":"                               \"Hint for the maximum number of parallel workers\"] = None,\n) -> dict[str, Any]:\n    \"\"\"Proxy the batch_execute tool to the Unity Editor transporter.\"\"\"\n    unity_instance = await get_unity_instance_from_context(ctx)\n\n    if not isinstance(commands, list) or not commands:\n        raise ValueError(\n            \"'commands' must be a non-empty list of command specifications\")\n\n    max_commands = await _get_max_commands_from_editor_state(ctx)\n    if len(commands) > max_commands:\n        raise ValueError(\n            f\"batch_execute supports up to {max_commands} commands (configured in Unity); received {len(commands)}\"\n        )\n\n    normalized_commands: list[dict[str, Any]] = []\n    for index, command in enumerate(commands):\n        if not isinstance(command, dict):\n            raise ValueError(\n                f\"Command at index {index} must be an object with 'tool' and 'params' keys\")\n\n        tool_name = command.get(\"tool\")\n        params = command.get(\"params\", {})\n\n        if not tool_name or not isinstance(tool_name, str):\n            raise ValueError(\n                f\"Command at index {index} is missing a valid 'tool' name\")\n\n        if params is None:\n            params = {}\n        if not isinstance(params, dict):\n            raise ValueError(\n                f\"Command '{tool_name}' must specify parameters as an object/dict\")\n\n        if \"unity_instance\" in params:\n            raise ValueError(\n                f\"Command '{tool_name}' at index {index} contains 'unity_instance'. \"","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/CoplayDev/unity-mcp/blob/c21bf496bca87d54e75bad048563c3adb1782081/Server/src/services/tools/batch_execute.py#L85-L121","documentation":"During per-command normalization in batch_execute, each element of the commands list must be a dict (JSON object). The check `not isinstance(command, dict)` rejects lists, strings, numbers, None, or any non-mapping type. The error message includes the offending index so the caller can locate the malformed entry. This is a structural contract violation: each command must have 'tool' and 'params' keys.","triggerScenarios":"A caller passes commands=[\"manage_gameobject\", {...}] mixing a bare string with objects; an LLM emits commands=[\"create_cube\"] treating batch_execute like a variadic string list; a JSON array where one element is a string or number instead of an object; a None element from a sparse array.","commonSituations":"An AI confuses batch_execute's command shape with a simpler API; a programmatic builder appends a tool name string instead of a {tool, params} dict; JSON deserialization of a mixed-type array; a copy-paste error mixing formats.","solutions":["Wrap each command as an object: {\"tool\": \"<name>\", \"params\": {...}}.","Check the error message for the index, then fix that specific entry in the commands list.","Validate the list shape before calling: all(isinstance(c, dict) for c in commands)."],"exampleFix":"// before\ncommands=[\"manage_gameobject\", {\"tool\": \"manage_material\", \"params\": {}}]\n// after\ncommands=[{\"tool\": \"manage_gameobject\", \"params\": {\"action\": \"create\"}}, {\"tool\": \"manage_material\", \"params\": {}}]","handlingStrategy":"validation","validationCode":"# Ensure every command is a dict before calling batch_execute\nif not all(isinstance(c, dict) for c in commands):\n    bad = [i for i, c in enumerate(commands) if not isinstance(c, dict)]\n    raise ValueError(f\"Commands at indices {bad} are not objects\")","typeGuard":"def all_commands_are_dicts(commands: list) -> bool:\n    return isinstance(commands, list) and all(isinstance(c, dict) for c in commands)","tryCatchPattern":null,"preventionTips":["Build commands as a list of dicts with 'tool' and 'params' keys from the start.","Never mix bare strings or other types into the commands list.","Validate list element types before submission."],"tags":["validation","batch-execute","input-shape","mcp-tool"],"backgroundTag":null,"analyzedSha":"c21bf496bca87d54e75bad048563c3adb1782081","analyzedAt":"2026-08-13T17:36:56.095Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}