{"record":{"id":"e584b062fa86638e","repo":"xai-org/grok-build","slug":"failed-to-set-mcp-preferences-permissions-e","errorCode":null,"errorMessage":"failed to set mcp preferences permissions: {e}","messagePattern":"failed to set mcp preferences permissions: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/util/config/mcp.rs","lineNumber":478,"sourceCode":"    let json = serde_json::to_string_pretty(prefs)?;\n    if let Some(parent) = path.parent() {\n        tokio::fs::create_dir_all(parent).await?;\n    }\n    let tmp = path.with_extension(format!(\n        \"json.tmp.{}{}\",\n        std::process::id(),\n        std::time::SystemTime::now()\n            .duration_since(std::time::UNIX_EPOCH)\n            .map(|d| d.as_nanos())\n            .unwrap_or(0)\n    ));\n    tokio::fs::write(&tmp, &json).await?;\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::PermissionsExt;\n        tokio::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600))\n            .await\n            .map_err(|e| anyhow::anyhow!(\"failed to set mcp preferences permissions: {e}\"))?;\n    }\n    tokio::fs::rename(&tmp, path).await?;\n    Ok(())\n}\n\n/// Restore a single server key after a failed setup (best-effort).\npub(crate) async fn restore_mcp_preference_server(\n    server_name: &str,\n    previous: Option<McpServerPreferences>,\n) -> Result<()> {\n    let load = load_mcp_preferences();\n    if !load.is_writable() {\n        return Ok(());\n    }\n    let mut prefs = load.file();\n    match previous {\n        Some(entry) => {\n            prefs.servers.insert(server_name.to_string(), entry);","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/util/config/mcp.rs#L460-L496","documentation":"save_mcp_preferences_to writes JSON to a temp file then tightens permissions to 0o600 (owner read/write) before an atomic rename; if tokio::fs::set_permissions fails the error is wrapped with this message. Failure means the OS refused the chmod (permissions, ownership, or filesystem limitation).","triggerScenarios":"Calling save_mcp_preferences (or the round-trip test) when set_permissions on the temp file fails — e.g. temp dir on a filesystem that disallows chmod, or the process lacks ownership of the temp file.","commonSituations":"Saving MCP preferences on Windows non-unix builds (skipped), on network/overlay filesystems with restricted chmod, or when TMPDIR points to an unusual mount; disk-full/quota errors surfaced as permission problems.","solutions":["Check ownership and permissions of the target directory (the process must own the temp file it just created).","Point the temp path to a normal local filesystem (the file is created next to `path`, so ensure the config directory is writable and supports chmod).","Inspect the chained io error ({e}) for the exact errno (EACCES, EPERM, EROFS) and fix accordingly.","If 0o600 cannot be enforced, decide whether to fail closed (current behavior) or fall back to default permissions with a warning."],"exampleFix":"// before\ntokio::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600))\n    .await\n    .map_err(|e| anyhow!(\"failed to set mcp preferences permissions: {e}\"))?;\n// after — warn instead of aborting when chmod is unsupported\nif let Err(e) = tokio::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600)).await {\n    tracing::warn!(\"could not tighten mcp preferences permissions: {e}\");\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check the config dir supports chmod (unix)\n#[cfg(unix)]\nlet ok = {\n    use std::os::unix::fs::PermissionsExt;\n    let probe = path.with_extension(\"perm-probe\");\n    std::fs::write(&probe, b\"\")?;\n    let r = std::fs::set_permissions(&probe, std::fs::Permissions::from_mode(0o600)).is_ok();\n    let _ = std::fs::remove_file(&probe);\n    r\n};","typeGuard":null,"tryCatchPattern":"match save_mcp_preferences(&prefs).await {\n    Err(e) if e.to_string().contains(\"failed to set mcp preferences permissions\") => {\n        log::warn!(\"chmod on config dir failed ({e}); writing with default perms\");\n        save_without_strict_perms(&prefs).await\n    }\n    other => other,\n}","preventionTips":["Keep config directories on local filesystems that support chmod","Ensure the process user owns its config directory","Don't point TMPDIR/config paths at exotic mounts (nfs, some overlays)","Monitor for EROFS/EACCES when deploying in hardened containers"],"tags":["rust","filesystem","permissions","config-save"],"backgroundTag":"file-permission-denied","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}