{"record":{"id":"7cd7713c9087023f","repo":"vllm-project/vllm","slug":"tool-response-messages-require-a-tool-call-id-use","errorCode":null,"errorMessage":"tool response messages require a tool_call_id; use ChatMessage::tool_response() instead","messagePattern":"tool response messages require a tool_call_id; use ChatMessage::tool_response\\(\\) instead","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"rust/src/chat/src/request.rs","lineNumber":228,"sourceCode":"    /// Tool response content associated with one prior assistant tool call.\n    ToolResponse {\n        content: ChatContent,\n        tool_call_id: String,\n    },\n}\n\nimpl ChatMessage {\n    /// Construct one chat message with plain string content.\n    pub fn text(role: ChatRole, text: impl Into<String>) -> Self {\n        let content: String = text.into();\n\n        match role {\n            ChatRole::System => Self::system(content),\n            ChatRole::Developer => Self::developer(content, None),\n            ChatRole::User => Self::user(content),\n            ChatRole::Assistant => Self::assistant_text(content),\n            ChatRole::ToolResponse => {\n                panic!(\n                    \"tool response messages require a tool_call_id; \\\n                     use ChatMessage::tool_response() instead\"\n                )\n            }\n        }\n    }\n\n    /// Construct one chat message with system role.\n    pub fn system(content: impl Into<ChatContent>) -> Self {\n        Self::System {\n            content: content.into(),\n        }\n    }\n\n    /// Construct one chat message with developer role.\n    pub fn developer(content: impl Into<ChatContent>, tools: Option<Vec<ChatTool>>) -> Self {\n        Self::Developer {\n            content: content.into(),","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/rust/src/chat/src/request.rs#L210-L246","documentation":"This is a `panic!`, not a Result error: `ChatMessage::text()` (request.rs:228) refuses to build a ToolResponse message because tool responses require a `tool_call_id` linking them to the assistant's tool call. The API deliberately has no sensible default, so misuse fails loudly. Use `ChatMessage::tool_response(...)` which takes the id.","triggerScenarios":"Calling `ChatMessage::text(ChatRole::ToolResponse, \"result body\")` — e.g. generic code that maps roles in a loop and routes ToolResponse through the text constructor.","commonSituations":"Deserializing/echoing conversation histories role-by-role with a match on role; porting client code where ToolResponse was treated as a plain role; replaying OpenAI-format histories.","solutions":["Replace the call with `ChatMessage::tool_response(tool_call_id, content)`.","Handle `ChatRole::ToolResponse` as a distinct arm in any role-matching code instead of funneling it through `text()`.","If replaying a history, look up the tool_call_id from the preceding assistant message's tool_calls."],"exampleFix":"// before\nlet msg = ChatMessage::text(ChatRole::ToolResponse, \"42\"); // panics\n\n// after\nlet msg = ChatMessage::tool_response(tool_call_id.clone(), \"42\");","handlingStrategy":"type-guard","validationCode":"for msg in &incoming_messages {\n    if msg.role == ChatRole::ToolResponse {\n        let id = resolve_tool_call_id(&assistant_msg, msg)?; // must exist\n        built.push(ChatMessage::tool_response(id, msg.content_text()));\n    }\n}","typeGuard":"fn needs_tool_call_id(role: ChatRole) -> bool {\n    matches!(role, ChatRole::ToolResponse)\n}","tryCatchPattern":"std::panic::set_hook is not a fix — this is a panic by design. Match on the role before constructing:\nlet msg = match role {\n    ChatRole::ToolResponse => ChatMessage::tool_response(tool_call_id, content),\n    other => ChatMessage::text(other, content),\n};","preventionTips":["Never route ChatRole::ToolResponse through ChatMessage::text(); handle it as its own match arm.","Carry the tool_call_id alongside the role when replaying conversation histories.","Add a unit test that builds every supported role to catch misuse at CI time."],"tags":["rust","panic","chat-message","tool-response","api-misuse"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}