{"record":{"id":"ef9dcf63e8e8c519","repo":"aaif-goose/goose","slug":"missing-tool-input","errorCode":null,"errorMessage":"Missing tool input","messagePattern":"Missing tool input","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-provider-types/src/formats/snowflake.rs","lineNumber":258,"sourceCode":"                    if !text.is_empty() {\n                        message = message.with_text(text.to_string());\n                    }\n                }\n            }\n            Some(\"tool_use\") => {\n                let id = content\n                    .get(\"tool_use_id\")\n                    .and_then(|i| i.as_str())\n                    .ok_or_else(|| anyhow!(\"Missing tool_use id\"))?;\n                let name = content\n                    .get(\"name\")\n                    .and_then(|n| n.as_str())\n                    .ok_or_else(|| anyhow!(\"Missing tool_use name\"))?\n                    .to_string();\n\n                let input = content\n                    .get(\"input\")\n                    .ok_or_else(|| anyhow!(\"Missing tool input\"))?\n                    .clone();\n\n                let tool_call = CallToolRequestParams::new(name).with_arguments(object(input));\n                message = message.with_tool_request(id, Ok(tool_call));\n            }\n            Some(\"thinking\") => {\n                let thinking = content\n                    .get(\"thinking\")\n                    .and_then(|t| t.as_str())\n                    .ok_or_else(|| anyhow!(\"Missing thinking content\"))?;\n                let signature = content\n                    .get(\"signature\")\n                    .and_then(|s| s.as_str())\n                    .ok_or_else(|| anyhow!(\"Missing thinking signature\"))?;\n                message = message.with_thinking(thinking, signature);\n            }\n            Some(\"redacted_thinking\") => {\n                let data = content","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-provider-types/src/formats/snowflake.rs#L240-L276","documentation":"For a Snowflake Cortex tool_use block, response_to_message requires the input key to be present (any JSON value; it is cloned and passed as tool arguments via object()). Unlike text fields it does not need to be a string, but it must exist. A tool_use block with tool_use_id and name but no input key fails with 'Missing tool input'.","triggerScenarios":"content_list contains {\"type\":\"tool_use\",\"tool_use_id\":\"...\",\"name\":\"...\"} with no \"input\" member. Happens when the model emits a tool call with no arguments and the endpoint omits the key entirely instead of sending \"input\": {}, or when a proxy strips empty objects.","commonSituations":"Zero-argument tools (no input) serialized without an input key; strict middlewares that drop empty fields; fixture authors assuming input is optional.","solutions":["Check the raw block: if \"input\" is simply absent for a no-arg tool, default it to an empty object on the producer side","Fix fixtures/mocks to always include \"input\": {} for tool_use blocks","If you control the parser, treat a missing input as empty arguments (see exampleFix) rather than an error"],"exampleFix":"// before\nlet input = content\n    .get(\"input\")\n    .ok_or_else(|| anyhow!(\"Missing tool input\"))?\n    .clone();\n\n// after - a tool call without arguments is valid\nlet input = content.get(\"input\").cloned().unwrap_or_else(|| serde_json::json!({}));","handlingStrategy":"validation","validationCode":"for block in content_list {\n    if block.get(\"type\").and_then(|t| t.as_str()) == Some(\"tool_use\")\n        && !block.get(\"input\").is_some()\n    {\n        anyhow::bail!(\"tool_use block without input key: {block}\");\n    }\n}","typeGuard":"fn tool_use_has_input(block: &serde_json::Value) -> bool {\n    if block.get(\"type\").and_then(|t| t.as_str()) != Some(\"tool_use\") {\n        return true;\n    }\n    block.get(\"input\").is_some()\n}","tryCatchPattern":"match response_to_message(&response) {\n    Ok(msg) => msg,\n    Err(err) if err.to_string().contains(\"Missing tool input\") => {\n        tracing::warn!(\"tool call without input key dropped: {err}\");\n        Message::assistant()\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Serialize zero-argument tool calls as \"input\": {} — never omit the key","Disable middleware that strips empty JSON fields on the response path","Keep fixtures byte-faithful to real Cortex output"],"tags":["rust","snowflake","cortex","tool-calls","parsing"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}