From 01d3c22c57fb84749a1d5692c0a1d98c49a125ad Mon Sep 17 00:00:00 2001 From: Riz Ashraf Date: Sun, 27 Sep 2026 09:44:04 +0100 Subject: [PATCH] Fix error swallowing by propagating JSON serialization errors to LLM --- server/src/handlers/env.rs | 8 ++--- server/src/handlers/graph.rs | 10 +++--- server/src/handlers/meta.rs | 52 +++++++++++++++---------------- server/src/handlers/notes.rs | 10 +++--- server/src/handlers/tasks.rs | 8 ++--- server/src/handlers/workspaces.rs | 30 +++++++++--------- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/server/src/handlers/env.rs b/server/src/handlers/env.rs index 79ce160..30d76ae 100644 --- a/server/src/handlers/env.rs +++ b/server/src/handlers/env.rs @@ -62,7 +62,7 @@ impl McpTool for ReadEnvFingerprintHandler { .read_with(|fps| fps.get(&req.namespace).cloned()); if let Some(fp) = data { let data = serde_json::to_string(&fp).unwrap_or_default(); - Ok(data.to_string()) + Ok(data) } else { Ok("{}".to_string()) } @@ -155,9 +155,9 @@ impl McpTool for GetEnvironmentDetailsHandler { .iter() .filter(|e| e.namespace == req.namespace) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } diff --git a/server/src/handlers/graph.rs b/server/src/handlers/graph.rs index ee0698f..001b6ef 100644 --- a/server/src/handlers/graph.rs +++ b/server/src/handlers/graph.rs @@ -380,8 +380,8 @@ impl McpTool for SearchNodesHandler { result.entities.insert(id, e); } } - serde_json::to_string(&result).unwrap_or_default() - }); + serde_json::to_string(&result).map_err(|e| e.to_string()) + })?; Ok(data) } } @@ -418,8 +418,8 @@ impl McpTool for OpenNodesHandler { result.entities.insert(name, e); } } - serde_json::to_string(&result).unwrap_or_default() - }); + serde_json::to_string(&result).map_err(|e| e.to_string()) + })?; Ok(data) } } @@ -620,7 +620,7 @@ impl McpTool for FindOrphansHandler { .collect::>() }); let data = serde_json::to_string(&orphans).unwrap_or_default(); - Ok(data.to_string()) + Ok(data) } } diff --git a/server/src/handlers/meta.rs b/server/src/handlers/meta.rs index eaf2be3..0461033 100644 --- a/server/src/handlers/meta.rs +++ b/server/src/handlers/meta.rs @@ -70,9 +70,9 @@ impl McpTool for QueryDecisionsHandler { } }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -129,9 +129,9 @@ impl McpTool for SearchErrorFixesHandler { || contains_ignore_ascii_case(&f.solution, &q) }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -180,8 +180,8 @@ impl McpTool for QueryRecentChangesHandler { async fn execute(&self, _args: Value, state: Arc) -> Result { let data = state .ledger - .read_with(|l| serde_json::to_string(l).unwrap_or_else(|_| "[]".to_string())); - Ok(data.to_string()) + .read_with(|l| serde_json::to_string(l).map_err(|e| e.to_string()))?; + Ok(data) } } @@ -229,7 +229,7 @@ impl McpTool for ReadPreferencesHandler { let data = state .prefs .read_with(|prefs| serde_json::to_string(prefs).unwrap_or_default()); - Ok(data.to_string()) + Ok(data) } } @@ -319,9 +319,9 @@ impl McpTool for ListTechDebtHandler { d.namespace == req.namespace && (req.include_resolved || !d.is_resolved) }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -370,8 +370,8 @@ impl McpTool for OmniSearchHandler { } } } - serde_json::to_value(&kg_entities).unwrap_or_default() - }); + serde_json::to_value(&kg_entities).map_err(|e| e.to_string()) + })?; let mut matched_tasks = std::collections::HashSet::new(); let mut matched_snippets = std::collections::HashSet::new(); @@ -407,8 +407,8 @@ impl McpTool for OmniSearchHandler { } }) .collect(); - serde_json::to_value(&filtered).unwrap_or_default() - }); + serde_json::to_value(&filtered).map_err(|e| e.to_string()) + })?; let snippets_json = state.snippets.read_with(|all_snippets| { let filtered: Vec<_> = all_snippets @@ -425,8 +425,8 @@ impl McpTool for OmniSearchHandler { } }) .collect(); - serde_json::to_value(&filtered).unwrap_or_default() - }); + serde_json::to_value(&filtered).map_err(|e| e.to_string()) + })?; let adrs_json = state.adrs.read_with(|all_adrs| { let filtered: Vec<_> = all_adrs @@ -445,8 +445,8 @@ impl McpTool for OmniSearchHandler { } }) .collect(); - serde_json::to_value(&filtered).unwrap_or_default() - }); + serde_json::to_value(&filtered).map_err(|e| e.to_string()) + })?; let q = req.query; let tech_debts_json = state.tech_debts.read_with(|debts| { @@ -469,8 +469,8 @@ impl McpTool for OmniSearchHandler { } }) .collect(); - serde_json::to_value(&filtered).unwrap_or_default() - }); + serde_json::to_value(&filtered).map_err(|e| e.to_string()) + })?; let memos_json = state.handoff_memos.read_with(|memos| { let filtered: Vec<_> = memos @@ -490,8 +490,8 @@ impl McpTool for OmniSearchHandler { } }) .collect(); - serde_json::to_value(&filtered).unwrap_or_default() - }); + serde_json::to_value(&filtered).map_err(|e| e.to_string()) + })?; let error_fixes_json = state.error_fixes.read_with(|fixes| { let filtered: Vec<_> = fixes @@ -501,8 +501,8 @@ impl McpTool for OmniSearchHandler { || contains_ignore_ascii_case(&f.solution, &q) }) .collect(); - serde_json::to_value(&filtered).unwrap_or_default() - }); + serde_json::to_value(&filtered).map_err(|e| e.to_string()) + })?; let report = serde_json::json!({ "knowledge_graph": kg_json, diff --git a/server/src/handlers/notes.rs b/server/src/handlers/notes.rs index dd33957..2d8a5ba 100644 --- a/server/src/handlers/notes.rs +++ b/server/src/handlers/notes.rs @@ -49,8 +49,8 @@ impl McpTool for ReadStickyNotesHandler { async fn execute(&self, _args: Value, state: Arc) -> Result { let data = state .sticky - .read_with(|s| serde_json::to_string(s).unwrap_or_else(|_| "[]".to_string())); - Ok(data.to_string()) + .read_with(|s| serde_json::to_string(s).map_err(|e| e.to_string()))?; + Ok(data) } } @@ -167,9 +167,9 @@ impl McpTool for ReadHandoffMemosHandler { } }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } diff --git a/server/src/handlers/tasks.rs b/server/src/handlers/tasks.rs index a31beb6..c7c4fbf 100644 --- a/server/src/handlers/tasks.rs +++ b/server/src/handlers/tasks.rs @@ -293,8 +293,8 @@ impl McpTool for ListActiveTasksHandler { status_match && branch_match }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; Ok(data) } } @@ -474,8 +474,8 @@ impl McpTool for ListMilestonesHandler { } }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; Ok(data) } } diff --git a/server/src/handlers/workspaces.rs b/server/src/handlers/workspaces.rs index 5b0bf70..cbac188 100644 --- a/server/src/handlers/workspaces.rs +++ b/server/src/handlers/workspaces.rs @@ -89,9 +89,9 @@ impl McpTool for ListPinnedFilesHandler { ns_match && branch_match }) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -154,9 +154,9 @@ impl McpTool for SearchSnippetsHandler { || contains_ignore_ascii_case(&s.language, &query) }) .collect(); - serde_json::to_string(&results).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&results).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -245,9 +245,9 @@ impl McpTool for LoadContextWorkspaceHandler { .iter() .filter(|w| w.namespace == req.namespace && w.name == req.name) .collect(); - serde_json::to_string(&filtered.first()).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered.first()).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -271,9 +271,9 @@ impl McpTool for ListContextWorkspacesHandler { serde_json::from_value(args).map_err(|e| e.to_string())?; let data = state.context_workspaces.read_with(|ws| { let filtered: Vec<_> = ws.iter().filter(|w| req.namespace.as_ref().map_or(true, |ns| &w.namespace == ns)).collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } } @@ -325,9 +325,9 @@ impl McpTool for GetPrChecklistHandler { .iter() .filter(|i| i.namespace == req.namespace) .collect(); - serde_json::to_string(&filtered).unwrap_or_default() - }); - Ok(data.to_string()) + serde_json::to_string(&filtered).map_err(|e| e.to_string()) + })?; + Ok(data) } }