{"record":{"id":"b42a4e25764364a4","repo":"xai-org/grok-build","slug":"failed-to-serialize-mcp-server-config-e","errorCode":null,"errorMessage":"failed to serialize MCP server config: {e}","messagePattern":"failed to serialize MCP server config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/util/config/mcp.rs","lineNumber":979,"sourceCode":"    server_name: &str,\n    config: &McpServerConfig,\n) -> Result<()> {\n    let mut root: TomlValue = match tokio::fs::read_to_string(&path).await {\n        Ok(s) => toml::from_str(&s).unwrap_or(TomlValue::Table(TomlMap::new())),\n        Err(_) => TomlValue::Table(TomlMap::new()),\n    };\n    let table = root\n        .as_table_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"config root is not a table\"))?;\n\n    let servers = table\n        .entry(\"mcp_servers\")\n        .or_insert_with(|| TomlValue::Table(TomlMap::new()))\n        .as_table_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"mcp_servers is not a table\"))?;\n\n    let serialized = toml::Value::try_from(config)\n        .map_err(|e| anyhow::anyhow!(\"failed to serialize MCP server config: {e}\"))?;\n    servers.insert(server_name.to_string(), serialized);\n\n    // Ensure the server isn't in the disabled list.\n    if let Some(arr) = table\n        .get_mut(\"disabled_mcp_servers\")\n        .and_then(|v| v.as_array_mut())\n    {\n        arr.retain(|v| v.as_str() != Some(server_name));\n        if arr.is_empty() {\n            table.remove(\"disabled_mcp_servers\");\n        }\n    }\n\n    let toml_str = toml::to_string_pretty(&root)?;\n    let tmp = path.with_extension(\"toml.tmp\");\n    if let Some(parent) = path.parent() {\n        let _ = tokio::fs::create_dir_all(parent).await;\n    }","sourceCodeStart":961,"sourceCodeEnd":997,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/util/config/mcp.rs#L961-L997","documentation":"save_mcp_server_config_at converts the in-memory MCP server config struct into a TOML value via toml::Value::try_from before merging it into config.toml. If the config struct contains types TOML cannot represent (e.g. non-string map keys, nested Options serialized as unit, or unsupported value types), serialization fails and this error is thrown. It wraps the underlying toml serializer error so the TOML detail is embedded in the message.","triggerScenarios":"Calling save_mcp_server_config / save_mcp_server_config_at with an McpServerConfig whose fields produce TOML-incompatible values — e.g. a map with non-string keys (toml only supports string keys), a nested None option, or a float that is NaN/infinity.","commonSituations":"Programmatically constructing server config from deserialized JSON (JSON keys can be integers, TOML keys cannot); hand-built configs with heterogeneous arrays (TOML requires homogeneous arrays); NaN/inf values coming from a numeric parser.","solutions":["Inspect the wrapped {e} TOML error to identify the offending field/value in the config struct","Convert non-string map keys to strings before saving (e.g. BTreeMap<String, T>)","Replace NaN/infinity or heterogeneous-typed values with TOML-compatible equivalents","Update the config struct's serde attributes to emit TOML-representable shapes"],"exampleFix":"// before\nlet serialized = toml::Value::try_from(config)\n    .map_err(|e| anyhow::anyhow!(\"failed to serialize MCP server config: {e}\"))?;\n// after\nlet config = sanitize_config_for_toml(config); // stringify map keys, replace NaN\nlet serialized = toml::Value::try_from(&config)\n    .map_err(|e| anyhow::anyhow!(\"failed to serialize MCP server config: {e}\"))?;","handlingStrategy":"validation","validationCode":"fn is_toml_serializable(config: &McpServerConfig) -> bool {\n    toml::Value::try_from(config).is_ok()\n}\nif !is_toml_serializable(&config) { eprintln!(\"config not TOML-serializable\"); }","typeGuard":"fn as_toml_value<T: serde::Serialize>(v: &T) -> Option<toml::Value> {\n    toml::Value::try_from(v).ok()\n}","tryCatchPattern":null,"preventionTips":["Keep MCP config map keys as Strings (TOML requires string keys)","Avoid NaN/infinity and heterogeneous arrays in config values","Add a round-trip test: deserialize -> serialize config with toml in CI","Sanitize JSON-derived configs before converting to TOML"],"tags":["toml","serialization","mcp","config"],"backgroundTag":"toml-serialization-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}