{"record":{"id":"74e7d9f6ce9a76a5","repo":"gitbutlerapp/gitbutler","slug":"failed-to-parse-parameters-e","errorCode":null,"errorMessage":"Failed to parse parameters: {e}","messagePattern":"Failed to parse parameters: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-tools/src/tool.rs","lineNumber":43,"sourceCode":"impl<'a> WorkspaceToolset<'a> {\n    pub fn new(ctx: &'a mut Context) -> Self {\n        WorkspaceToolset {\n            ctx,\n            tools: BTreeMap::new(),\n            commit_mapping: HashMap::new(),\n        }\n    }\n\n    fn call_tool_inner(\n        &mut self,\n        name: &str,\n        parameters: &str,\n    ) -> anyhow::Result<serde_json::Value> {\n        let tool = self\n            .get(name)\n            .ok_or_else(|| anyhow::anyhow!(\"Tool '{name}' not found\"))?;\n        let params: serde_json::Value = serde_json::from_str(parameters)\n            .map_err(|e| anyhow::anyhow!(\"Failed to parse parameters: {e}\"))?;\n        tool.call(params, self.ctx, &mut self.commit_mapping)\n    }\n}\n\nimpl Toolset for WorkspaceToolset<'_> {\n    fn register_tool<T: Tool>(&mut self, tool: T) {\n        self.tools.insert(tool.name(), Arc::new(tool));\n    }\n\n    fn get(&self, name: &str) -> Option<Arc<dyn Tool>> {\n        self.tools.get(name).cloned()\n    }\n\n    fn list(&self) -> Vec<Arc<dyn Tool>> {\n        self.tools.values().cloned().collect()\n    }\n\n    fn call_tool(&mut self, name: &str, parameters: &str) -> serde_json::Value {","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-tools/src/tool.rs#L25-L61","documentation":"WorkspaceToolset::call_tool_inner failed to deserialize the `parameters` argument with serde_json::from_str — the caller passed a string that is not valid JSON. Parameters must be a complete JSON document (typically a JSON object), not bare key=value text or a truncated payload.","triggerScenarios":"Calling call_tool(name, \"branch: main\") or passing a string with smart quotes, trailing commas, single-quoted keys, or a payload truncated by a size limit; note call_tool itself swallows this into an {\"error\": ...} JSON value rather than panicking.","commonSituations":"LLM emits malformed JSON for tool arguments; string interpolation builds parameters without json!()/serde serialization; encoding issues (BOM, non-UTF8) corrupt the payload.","solutions":["Serialize parameters with a real JSON serializer (serde_json::to_string, JSON.stringify) instead of hand-building the string","Validate the string parses before calling: parse it as serde_json::Value in a prior step","When consuming results, check for the {\"error\": \"Failed to call tool ...\"} key that call_tool returns on failure"],"exampleFix":"// before\ntoolset.call_tool(\"get_stack\", format!(\"stack_id={}\", id)); // not JSON\n// after\nlet params = serde_json::to_string(&serde_json::json!({ \"stack_id\": id }))?;\ntoolset.call_tool(\"get_stack\", &params);","handlingStrategy":"validation","validationCode":"// validate before calling — parse to Value first\nlet value: serde_json::Value = serde_json::from_str(params_str)\n    .with_context(|| \"tool parameters must be valid JSON\")?;\nassert!(value.is_object(), \"tool parameters should be a JSON object\");\ntoolset.call_tool(name, params_str);","typeGuard":null,"tryCatchPattern":"when (result.error) {\n  if (result.error.includes(\"Failed to parse parameters\")) { /* re-serialize args with JSON.stringify and retry once */ }\n}","preventionTips":["Always serialize tool arguments with a JSON library, never string interpolation","Check call_tool's returned object for an \"error\" key — it does not panic on bad input","In LLM loops, run model-emitted arguments through JSON.parse and repair before invoking"],"tags":["rust","json","tool-calling","input-validation","but-tools"],"backgroundTag":"invalid-json-payload","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}