xai-org/grok-build · error

failed to set mcp preferences permissions: {e}

Error message

failed to set mcp preferences permissions: {e}

What it means

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).

Source

Thrown at crates/codegen/xai-grok-shell/src/util/config/mcp.rs:478

    let json = serde_json::to_string_pretty(prefs)?;
    if let Some(parent) = path.parent() {
        tokio::fs::create_dir_all(parent).await?;
    }
    let tmp = path.with_extension(format!(
        "json.tmp.{}{}",
        std::process::id(),
        std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_nanos())
            .unwrap_or(0)
    ));
    tokio::fs::write(&tmp, &json).await?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        tokio::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600))
            .await
            .map_err(|e| anyhow::anyhow!("failed to set mcp preferences permissions: {e}"))?;
    }
    tokio::fs::rename(&tmp, path).await?;
    Ok(())
}

/// Restore a single server key after a failed setup (best-effort).
pub(crate) async fn restore_mcp_preference_server(
    server_name: &str,
    previous: Option<McpServerPreferences>,
) -> Result<()> {
    let load = load_mcp_preferences();
    if !load.is_writable() {
        return Ok(());
    }
    let mut prefs = load.file();
    match previous {
        Some(entry) => {
            prefs.servers.insert(server_name.to_string(), entry);

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check ownership and permissions of the target directory (the process must own the temp file it just created).
  2. 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).
  3. Inspect the chained io error ({e}) for the exact errno (EACCES, EPERM, EROFS) and fix accordingly.
  4. If 0o600 cannot be enforced, decide whether to fail closed (current behavior) or fall back to default permissions with a warning.

Example fix

// before
tokio::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600))
    .await
    .map_err(|e| anyhow!("failed to set mcp preferences permissions: {e}"))?;
// after — warn instead of aborting when chmod is unsupported
if let Err(e) = tokio::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600)).await {
    tracing::warn!("could not tighten mcp preferences permissions: {e}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check the config dir supports chmod (unix)
#[cfg(unix)]
let ok = {
    use std::os::unix::fs::PermissionsExt;
    let probe = path.with_extension("perm-probe");
    std::fs::write(&probe, b"")?;
    let r = std::fs::set_permissions(&probe, std::fs::Permissions::from_mode(0o600)).is_ok();
    let _ = std::fs::remove_file(&probe);
    r
};

Try / catch

match save_mcp_preferences(&prefs).await {
    Err(e) if e.to_string().contains("failed to set mcp preferences permissions") => {
        log::warn!("chmod on config dir failed ({e}); writing with default perms");
        save_without_strict_perms(&prefs).await
    }
    other => other,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/e584b062fa86638e. Report an issue: GitHub.