{"record":{"id":"cbb9499d1ebe6c41","repo":"xai-org/grok-build","slug":"failed-to-write-e","errorCode":null,"errorMessage":"failed to write {}: {e}","messagePattern":"failed to write (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/util/config/mcp.rs","lineNumber":809,"sourceCode":"        Err(parse_err) => {\n            return Err(anyhow::anyhow!(\n                \"refusing to overwrite unparseable {}: {}; fix the syntax before retrying\",\n                path.display(),\n                parse_err\n            ));\n        }\n    };\n    let before = toml::to_string_pretty(&root)?;\n    let table = root\n        .as_table_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"config root is not a table\"))?;\n    f(table);\n    let toml_str = toml::to_string_pretty(&root)?;\n    if before == toml_str {\n        return Ok(false);\n    }\n    super::persist::atomic_write_string(path, &toml_str)\n        .map_err(|e| anyhow::anyhow!(\"failed to write {}: {e}\", path.display()))?;\n    Ok(true)\n}\n\n/// Flip sticky project `enabled = false` → true with toml_edit (comments kept).\nasync fn clear_sticky_project_disabled_at(\n    path: &std::path::Path,\n    server_name: &str,\n) -> Result<bool> {\n    let original = match tokio::fs::read_to_string(path).await {\n        Ok(s) => s,\n        Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(false),\n        Err(e) => {\n            return Err(anyhow::anyhow!(\"failed to read {}: {e}\", path.display()));\n        }\n    };\n    let mut doc: toml_edit::DocumentMut = original\n        .parse()\n        .map_err(|e| anyhow::anyhow!(\"refusing to rewrite unparseable {}: {e}\", path.display()))?;","sourceCodeStart":791,"sourceCodeEnd":827,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/util/config/mcp.rs#L791-L827","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\n$ chmod 444 ~/.config/app/config.toml\n// after\n$ chmod 644 ~/.config/app/config.toml","handlingStrategy":"try-catch","validationCode":"// pre-flight write check\nlet probe = path.with_extension(\"probe\");\nstd::fs::write(&probe, b\"\").map_err(|e| format!(\"config dir not writable: {e}\"))?;\nstd::fs::remove_file(&probe).ok();","typeGuard":null,"tryCatchPattern":"match save_mcp_server_enabled_in(...) {\n    Err(e) if e.to_string().starts_with(\"failed to write\") => {\n        eprintln!(\"check permissions/free space for config file: {e}\");\n    }\n    r => r?,\n}","preventionTips":["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"],"tags":["io","filesystem","toml","write-failure"],"backgroundTag":"config-write-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}