janhq/jan · critical
Failed to serialize MCP settings
Error message
Failed to serialize MCP settings
What it means
This is a panic (.expect) from serde_json::to_value(&settings) when serializing the McpSettings struct to inject it into the config JSON during save_mcp_configs. Since settings was just parsed from the same JSON (via parse_mcp_settings), a serialization failure here indicates a structural problem in the McpSettings Serialize derive — a non-serializable field type, or a custom Serialize impl that errors. In practice this should never fire; if it does, it points to a code bug rather than user data.
Source
Thrown at src-tauri/src/core/mcp/commands.rs:801
) -> Result<(), String> {
let mut path = get_jan_data_folder_path(app.clone());
path.push("mcp_config.json");
log::info!("save mcp configs, path: {path:?}");
let mut config_value: Value =
serde_json::from_str(&configs).map_err(|e| format!("Invalid MCP config payload: {e}"))?;
if !config_value.is_object() {
return Err("MCP config must be a JSON object".to_string());
}
let config_object = config_value.as_object_mut().unwrap();
let settings = parse_mcp_settings(config_object.get("mcpSettings"));
if !config_object.contains_key("mcpSettings") {
config_object.insert(
"mcpSettings".to_string(),
serde_json::to_value(&settings).expect("Failed to serialize MCP settings"),
);
}
if !config_object.contains_key("mcpServers") {
config_object.insert("mcpServers".to_string(), json!({}));
}
fs::write(
&path,
serde_json::to_string_pretty(&config_value)
.map_err(|e| format!("Failed to serialize MCP config: {e}"))?,
)
.map_err(|e| e.to_string())?;
{
let state = app.state::<AppState>();
let mut settings_guard = state.mcp_settings.lock().await;
*settings_guard = settings;View on GitHub (pinned to fad3f12a14)
Solutions
- Inspect the McpSettings struct definition for any field lacking a Serialize impl.
- Check for custom serde attributes that may fail on specific enum variants.
- Add a unit test that round-trips McpSettings through serde_json to catch regressions.
- Replace .expect with a proper error return to avoid crashing the app on this path.
Example fix
// before
serde_json::to_value(&settings).expect("Failed to serialize MCP settings")
// after
serde_json::to_value(&settings)
.map_err(|e| format!("Failed to serialize MCP settings: {e}"))? Defensive patterns
Strategy: try-catch
Validate before calling
// Add a round-trip test to catch serialization regressions early
#[test]
fn mcp_settings_roundtrip() {
let settings = McpSettings::default();
let value = serde_json::to_value(&settings)
.expect("McpSettings must be serializable");
let back: McpSettings = serde_json::from_value(value)
.expect("McpSettings must be deserializable from its own serialization");
assert_eq!(settings, back);
} Try / catch
// Replace .expect with a proper error
let settings_value = serde_json::to_value(&settings)
.map_err(|e| format!("Failed to serialize MCP settings: {e}"))?;
config_object.insert("mcpSettings".to_string(), settings_value); Prevention
- Run a round-trip serialization test for McpSettings in CI.
- Never add non-Serialize fields to McpSettings without testing the config save path.
- Use .map_err instead of .expect for any serialization in a request-handling code path.
- Add #[derive(Serialize, Deserialize)] tests for all config structs.
When it happens
Trigger: A new field added to McpSettings that does not implement Serialize. A custom serde attribute (e.g. #[serde(serialize_with=...)]) that panics on certain values. An interior enum variant that serde cannot represent as a map value. PhantomData or non-serializable marker types in the struct.
Common situations: Plugin version mismatch where the struct changed but the binary is old. Manual edits to the McpSettings struct introducing a non-serializable type. A serde rename/tag conflict causing recursive serialization failure.
Related errors
- Failed to get current exe path
- Executable must have a parent directory
- Failed to get app data dir
- model.yml not found for ${modelId}
- Backend setup was not successful. Please restart the app in
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/091e458e469c764d.
Report an issue: GitHub.