Log malformed tool argument JSON instead of silently falling back to string
Parsing tc.arguments with unwrap_or_else silently converts invalid JSON to a string value, which can mask real parsing errors. Add logging at three sites where this pattern occurs: - pretty_tool_arguments (chat.rs): logs both JSON parse errors and pretty-print failures - ToolCall event creation (main.rs): logs JSON parse errors when sending tool call updates to ACP clients - Permission request creation (main.rs): logs JSON parse errors when requesting permission for a tool call This allows developers to identify malformed argument JSON in logs, while maintaining backward compatibility (still falling back to string repr on error). Co-Authored-By: siGit Code <noreply@sigit.si>
paydii committed
Aug 30, 2026 at 13:58 UTC
4430d520e364ac7b7ae56ad7d17e5621e2ed94b6
2 files changed
+19
-8
src/chat.rs
+11
-5
@@ -186,13 +186,19 @@ pub(crate) fn tool_title(name: &str, arguments_json: &str) -> String {
186
}
187
188
/// Pretty-print a tool call's JSON arguments for the expanded view; malformed
189
-/// JSON is shown raw.
189
+/// JSON is logged and shown raw.
190
#[cfg_attr(not(unix), allow(dead_code))]
191
pub(crate) fn pretty_tool_arguments(arguments_json: &str) -> String {
192
- serde_json::from_str::<serde_json::Value>(arguments_json)
193
- .ok()
194
- .and_then(|value| serde_json::to_string_pretty(&value).ok())
195
- .unwrap_or_else(|| arguments_json.to_string())
192
+ match serde_json::from_str::<serde_json::Value>(arguments_json) {
193
+ Ok(value) => serde_json::to_string_pretty(&value).unwrap_or_else(|e| {
194
+ log::warn!("failed to pretty-print tool arguments: {e}");
195
+ arguments_json.to_string()
196
+ }),
197
+ Err(e) => {
198
+ log::warn!("malformed JSON in tool arguments: {e}");
199
+ arguments_json.to_string()
200
+ }
201
+ }
202
}
203
204
/// The tail of a tool's output for display under an expanded tool entry,
src/main.rs
+8
-3
@@ -1523,7 +1523,10 @@ impl SiGitAgent {
1523
// leaving an otherwise working tool round visually indistinct
1524
// from a stalled response.
1525
let raw_input: serde_json::Value = serde_json::from_str(&tc.arguments)
1526
- .unwrap_or_else(|_| serde_json::Value::String(tc.arguments.clone()));
1526
+ .unwrap_or_else(|e| {
1527
+ log::warn!("malformed JSON in tool arguments for '{}': {e}", tc.name);
1528
+ serde_json::Value::String(tc.arguments.clone())
1529
+ });
1530
self.send_tool_call_update(
1531
cx,
1532
session_id.clone(),
@@ -1734,8 +1737,10 @@ impl SiGitAgent {
1737
} else {
1738
format!("{tool_name}({args_preview})")
1739
};
1737
- let raw_input: serde_json::Value = serde_json::from_str(arguments)
1738
- .unwrap_or_else(|_| serde_json::Value::String(arguments.to_string()));
1740
+ let raw_input: serde_json::Value = serde_json::from_str(arguments).unwrap_or_else(|e| {
1741
+ log::warn!("malformed JSON in tool arguments for '{}': {e}", tool_name);
1742
+ serde_json::Value::String(arguments.to_string())
1743
+ });
1744
1745
let request = RequestPermissionRequest::new(
1746
session_id.clone(),