{"record":{"id":"2a03ca0ebcf500ee","repo":"aaif-goose/goose","slug":"missing-tool-use-name-2a03ca","errorCode":null,"errorMessage":"Missing tool_use name","messagePattern":"Missing tool_use name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-provider-types/src/formats/snowflake.rs","lineNumber":253,"sourceCode":"    // Process all content items in the list\n    for content in content_list {\n        match content.get(\"type\").and_then(|t| t.as_str()) {\n            Some(\"text\") => {\n                if let Some(text) = content.get(\"text\").and_then(|t| t.as_str()) {\n                    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())","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-provider-types/src/formats/snowflake.rs#L235-L271","documentation":"While parsing a Snowflake Cortex content_list entry of type \"tool_use\", response_to_message requires a string name field (the tool name to put into CallToolRequestParams). A tool_use block whose name key is absent or not a string fails with 'Missing tool_use name'. Note the id is extracted first, so this error implies tool_use_id was present.","triggerScenarios":"A {\"type\":\"tool_use\",\"tool_use_id\":\"...\"} block in content_list with no name key or a non-string name (null, number). Occurs with truncated model output, API shape drift, or gateways that forward tool calls without resolving the tool name.","commonSituations":"Cortex returning a partially-formed tool call (name elided under token pressure); fixtures written with only id+input; schema change renaming name to tool_name.","solutions":["Inspect the raw content_list entry: confirm \"name\" exists and is a JSON string","If the field was renamed upstream (e.g. tool_name), align the parser/config with the current Snowflake Cortex schema","Fix test fixtures to include \"name\" on tool_use blocks","If upstream cannot be corrected, skip the block with a warn instead of aborting the whole conversion"],"exampleFix":"// before\nlet 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// after - tolerate a missing name with a placeholder and a warning\nlet name = match content.get(\"name\").and_then(|n| n.as_str()) {\n    Some(n) => n.to_string(),\n    None => {\n        tracing::warn!(\"tool_use block without name; using placeholder\");\n        \"unknown_tool\".to_string()\n    }\n};","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(\"name\").and_then(|n| n.as_str()).is_none()\n    {\n        anyhow::bail!(\"tool_use block without string name: {block}\");\n    }\n}","typeGuard":"fn tool_use_has_name(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(\"name\").and_then(|v| v.as_str()).is_some()\n}","tryCatchPattern":"match response_to_message(&response) {\n    Ok(msg) => msg,\n    Err(err) if err.to_string().contains(\"Missing tool_use name\") => {\n        tracing::warn!(\"tool call without name dropped: {err}\");\n        Message::assistant()\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Always emit \"name\" alongside \"tool_use_id\" in mocks and recorded traffic","Validate tool schemas advertised to Cortex so the model can only call named tools","Watch for schema renames (name vs tool_name) after endpoint upgrades"],"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"}