gitbutlerapp/gitbutler · error · anyhow::Error
Failed to parse parameters: {e}
Error message
Failed to parse parameters: {e} What it means
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.
Source
Thrown at crates/but-tools/src/tool.rs:43
impl<'a> WorkspaceToolset<'a> {
pub fn new(ctx: &'a mut Context) -> Self {
WorkspaceToolset {
ctx,
tools: BTreeMap::new(),
commit_mapping: HashMap::new(),
}
}
fn call_tool_inner(
&mut self,
name: &str,
parameters: &str,
) -> anyhow::Result<serde_json::Value> {
let tool = self
.get(name)
.ok_or_else(|| anyhow::anyhow!("Tool '{name}' not found"))?;
let params: serde_json::Value = serde_json::from_str(parameters)
.map_err(|e| anyhow::anyhow!("Failed to parse parameters: {e}"))?;
tool.call(params, self.ctx, &mut self.commit_mapping)
}
}
impl Toolset for WorkspaceToolset<'_> {
fn register_tool<T: Tool>(&mut self, tool: T) {
self.tools.insert(tool.name(), Arc::new(tool));
}
fn get(&self, name: &str) -> Option<Arc<dyn Tool>> {
self.tools.get(name).cloned()
}
fn list(&self) -> Vec<Arc<dyn Tool>> {
self.tools.values().cloned().collect()
}
fn call_tool(&mut self, name: &str, parameters: &str) -> serde_json::Value {View on GitHub (pinned to caf1f223d3)
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
Example fix
// before
toolset.call_tool("get_stack", format!("stack_id={}", id)); // not JSON
// after
let params = serde_json::to_string(&serde_json::json!({ "stack_id": id }))?;
toolset.call_tool("get_stack", ¶ms); Defensive patterns
Strategy: validation
Validate before calling
// validate before calling — parse to Value first
let value: serde_json::Value = serde_json::from_str(params_str)
.with_context(|| "tool parameters must be valid JSON")?;
assert!(value.is_object(), "tool parameters should be a JSON object");
toolset.call_tool(name, params_str); Try / catch
when (result.error) {
if (result.error.includes("Failed to parse parameters")) { /* re-serialize args with JSON.stringify and retry once */ }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: LLM emits malformed JSON for tool arguments; string interpolation builds parameters without json!()/serde serialization; encoding issues (BOM, non-UTF8) corrupt the payload.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Tool '{name}' not found
- existing GitMeta key '{associated_targets_key}' is not a str
- existing GitMeta key '{detail_key}' is not a string
- transcript contains malformed JSON before the final record
- Failed to parse response: {e}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/74e7d9f6ce9a76a5.
Report an issue: GitHub.