{"record":{"id":"3643f44469ef5d6b","repo":"zylon-ai/private-gpt","slug":"tool-result-block-references-an-unknown-tool-use-i","errorCode":null,"errorMessage":"Tool result block references an unknown tool use ID: {block.tool_use_id}","messagePattern":"Tool result block references an unknown tool use ID: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"private_gpt/server/chat/chat_models.py","lineNumber":403,"sourceCode":"        tool_uses_ids: set[str] = set()\n        tool_results_ids: set[str] = set()\n        for message in self.messages:\n            if isinstance(message.content, list):\n                for block in message.content:\n                    if block is None:\n                        raise ValueError(\"Block cannot be None\")\n                    elif isinstance(block, ToolUseBlock):\n                        if message.role != \"assistant\":\n                            raise ValueError(\n                                f\"Tool use blocks can only be used in assistant messages: {message}\"\n                            )\n                        if block.id in tool_uses_ids:\n                            raise ValueError(f\"Duplicate tool use ID found: {block.id}\")\n                        tool_uses_ids.add(block.id)\n\n                    elif isinstance(block, ToolResultBlock):\n                        if block.tool_use_id not in tool_uses_ids:\n                            raise ValueError(\n                                f\"Tool result block references an unknown tool use ID: {block.tool_use_id}\"\n                            )\n                        tool_results_ids.add(block.tool_use_id)\n\n                    elif isinstance(block, TLDRBlock):\n                        if message.role != \"assistant\":\n                            raise ValueError(\n                                f\"TLDR blocks can only be used in assistant messages: {message}\"\n                            )\n\n        if tool_results_ids != tool_uses_ids:\n            raise ValueError(\n                \"Tool result blocks must match the tool use IDs in the same message.\"\n                f\" Found tool use IDs: {tool_uses_ids}, but tool result IDs: {tool_results_ids}\"\n            )\n\n        return self\n","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/server/chat/chat_models.py#L385-L421","documentation":"Raised while validating ChatMessages: a ToolResultBlock references a tool_use_id that was never declared by any preceding ToolUseBlock in the message list. The validator first collects all ToolUseBlock ids (assistant messages only) and then checks each ToolResultBlock against that set; an unmatched reference means the conversation history is inconsistent — a tool result without its originating tool call.","triggerScenarios":"Sending a user/tool message containing a ToolResultBlock whose tool_use_id is misspelled, was generated client-side without a matching ToolUseBlock, or whose assistant tool_use message was dropped (e.g. history truncation removed the assistant turn but kept the result).","commonSituations":"Sliding-window history pruning that cuts assistant tool_use turns but keeps tool result turns; clients that synthesize tool results manually (e.g. 'error' placeholder results) with arbitrary ids; migrating histories where ids were regenerated.","solutions":["Ensure every ToolResultBlock.tool_use_id exactly matches the id of a ToolUseBlock present earlier in the same messages array","When trimming history, remove each tool_use/tool_result pair together, never the tool_use alone","If you inject synthetic tool results, first inject (or keep) the corresponding assistant tool_use block with the same id"],"exampleFix":"# before\nmessages = [\n  {\"role\": \"user\", \"content\": [{\"type\": \"tool_result\", \"tool_use_id\": \"tu_999\", \"content\": \"ok\"}]},\n]\n\n# after\nmessages = [\n  {\"role\": \"assistant\", \"content\": [{\"type\": \"tool_use\", \"id\": \"tu_999\", \"name\": \"search\", \"input\": {\"q\": \"x\"}}]},\n  {\"role\": \"user\", \"content\": [{\"type\": \"tool_result\", \"tool_use_id\": \"tu_999\", \"content\": \"ok\"}]},\n]","handlingStrategy":"validation","validationCode":"use_ids = {b.id for m in messages if m.role == \"assistant\" for b in (m.content or []) if isinstance(b, ToolUseBlock)}\nresult_ids = [b.tool_use_id for m in messages for b in (m.content or []) if isinstance(b, ToolResultBlock)]\nmissing = [r for r in result_ids if r not in use_ids]\nassert not missing, f\"tool results without matching tool_use: {missing}\"","typeGuard":"def tool_results_are_grounded(messages: list) -> bool:\n    use_ids = set()\n    for m in messages:\n        blocks = m.get(\"content\", []) if isinstance(m, dict) else (m.content or [])\n        for b in blocks:\n            t = b.get(\"type\") if isinstance(b, dict) else getattr(b, \"type\", None)\n            if t == \"tool_use\":\n                use_ids.add(b.get(\"id\") if isinstance(b, dict) else b.id)\n            if t == \"tool_result\":\n                rid = b.get(\"tool_use_id\") if isinstance(b, dict) else b.tool_use_id\n                if rid not in use_ids:\n                    return False\n    return True","tryCatchPattern":"try:\n    ChatMessages(messages=msgs)\nexcept ValueError as e:\n    if \"unknown tool use ID\" in str(e):\n        drop_orphan_tool_results(msgs)\n    else:\n        raise","preventionTips":["Treat tool_use/tool_result as an atomic pair when editing history","Never synthesize tool results with invented ids","Validate pair grounding before sending the request"],"tags":["chat","tool-use","validation","messages"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}