xai-org/grok-build · error

failed to write {}: {e}

Error message

failed to write {}: {e}

What it means

After mutating the TOML root, write_toml_table_if_changed serializes it and persists via atomic_write_string. If that write fails, the I/O error is wrapped with the target path and rethrown. This means the change was computed but could not be durably saved.

Source

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

        Err(parse_err) => {
            return Err(anyhow::anyhow!(
                "refusing to overwrite unparseable {}: {}; fix the syntax before retrying",
                path.display(),
                parse_err
            ));
        }
    };
    let before = toml::to_string_pretty(&root)?;
    let table = root
        .as_table_mut()
        .ok_or_else(|| anyhow::anyhow!("config root is not a table"))?;
    f(table);
    let toml_str = toml::to_string_pretty(&root)?;
    if before == toml_str {
        return Ok(false);
    }
    super::persist::atomic_write_string(path, &toml_str)
        .map_err(|e| anyhow::anyhow!("failed to write {}: {e}", path.display()))?;
    Ok(true)
}

/// Flip sticky project `enabled = false` → true with toml_edit (comments kept).
async fn clear_sticky_project_disabled_at(
    path: &std::path::Path,
    server_name: &str,
) -> Result<bool> {
    let original = match tokio::fs::read_to_string(path).await {
        Ok(s) => s,
        Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(false),
        Err(e) => {
            return Err(anyhow::anyhow!("failed to read {}: {e}", path.display()));
        }
    };
    let mut doc: toml_edit::DocumentMut = original
        .parse()
        .map_err(|e| anyhow::anyhow!("refusing to rewrite unparseable {}: {e}", path.display()))?;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check permissions on the config file and its directory (ls -l) and fix with chmod/chown
  2. Verify the parent directory exists and the filesystem is writable (not mounted read-only)
  3. Free disk space / check quota if ENOSPC was reported
  4. Retry the operation once the filesystem issue is resolved

Example fix

// before
$ chmod 444 ~/.config/app/config.toml
// after
$ chmod 644 ~/.config/app/config.toml
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight write check
let probe = path.with_extension("probe");
std::fs::write(&probe, b"").map_err(|e| format!("config dir not writable: {e}"))?;
std::fs::remove_file(&probe).ok();

Try / catch

match save_mcp_server_enabled_in(...) {
    Err(e) if e.to_string().starts_with("failed to write") => {
        eprintln!("check permissions/free space for config file: {e}");
    }
    r => r?,
}

Prevention

When it happens

Trigger: save_mcp_server_enabled_in / save_user_mcp_server_enabled detect a change and call atomic_write_string, which fails due to filesystem-level errors (permissions, missing parent directory, disk full, target is a directory).

Common situations: Read-only filesystem or config directory; file owned by another user; running from a sandbox/container with a read-only mount; disk quota exceeded; parent directory removed between read and write.

Related errors


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