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
- Check permissions on the config file and its directory (ls -l) and fix with chmod/chown
- Verify the parent directory exists and the filesystem is writable (not mounted read-only)
- Free disk space / check quota if ENOSPC was reported
- 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
- Ensure the config directory exists and is writable by the running user
- Avoid read-only mounts for config paths; check disk space regularly
- Prefer atomic_write_string-style persistence to avoid torn writes
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
- failed to read {}: {e}
- Failed to create agent config: {e}
- Failed to set working directory to {:?}: {}
- failed to create chrome trace {:?}: {}
- failed to read {}: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/cbb9499d1ebe6c41.
Report an issue: GitHub.