{"record":{"id":"d914e6e020e962d1","repo":"xai-org/grok-build","slug":"failed-to-read-e","errorCode":null,"errorMessage":"failed to read {}: {e}","messagePattern":"failed to read (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/util/config/mcp.rs","lineNumber":786,"sourceCode":"/// files (no wipe-to-empty), unique tmp + mode preserve via\n/// [`super::persist::atomic_write_string`], and the user-config write lock.\nasync fn write_toml_table_if_changed(\n    path: &std::path::Path,\n    f: impl FnOnce(&mut TomlMap<String, TomlValue>),\n) -> Result<bool> {\n    let is_user = path == config_path().as_path();\n    let _guard = if is_user {\n        Some(super::persist::lock_config_writes().await)\n    } else {\n        None\n    };\n\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 && is_user => String::new(),\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 root = match super::persist::parse_existing_config_toml(&original) {\n        Ok(v) => v,\n        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)?;","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/util/config/mcp.rs#L768-L804","documentation":"write_toml_table_if_changed reads the existing TOML file before rewriting it. NotFound is tolerated (empty for user configs, no-op otherwise), but any other read error is wrapped in this message. It is an I/O-level failure (permissions, path issues, is-a-directory), not a parse failure.","triggerScenarios":"Calling save_mcp_server_enabled_in / save_user_mcp_server_enabled when reading the config path fails with a non-NotFound I/O error — e.g. Permission denied, the path is a directory, or a device error.","commonSituations":"Config file owned by another user / read-only mount; a directory was accidentally created at the config path; network home directories temporarily unavailable.","solutions":["Check the chained io error ({e}) and fix the OS-level cause (chmod/chown the file, free the mount).","Ensure the config path is a regular file, not a directory; remove/replace it if so.","Run the process as a user with read access to the config file.","If the file is unreadable and disposable, move it aside (backup) and let the tool write a fresh one."],"exampleFix":"// before\nErr(e) => { return Err(anyhow!(\"failed to read {}: {e}\", path.display())); }\n// after — add context for the operator\nErr(e) => {\n    return Err(e).with_context(|| format!(\n        \"failed to read {}: check file permissions and that it is a regular file\",\n        path.display()\n    ));\n}","handlingStrategy":"validation","validationCode":"fn config_readable_file(path: &Path) -> Result<(), String> {\n    let md = std::fs::metadata(path).map_err(|e| e.to_string())?;\n    if !md.is_file() { return Err(format!(\"{} is not a regular file\", path.display())); }\n    std::fs::File::open(path).map(|_| ()).map_err(|e| e.to_string())\n}\n// invoke before save_mcp_server_enabled_in / save_user_mcp_server_enabled","typeGuard":null,"tryCatchPattern":"match save_user_mcp_server_enabled(name, enabled).await {\n    Err(e) if e.to_string().starts_with(\"failed to read \") => {\n        log::error!(\"config unreadable: {e}; check permissions/path is a file\");\n        fix_permissions_or_relocate(&cfg_path)?;\n        save_user_mcp_server_enabled(name, enabled).await\n    }\n    other => other,\n}","preventionTips":["Ensure the config path is always a regular file, never a directory","Run the tool as a user with read/write access to the config","Avoid read-only or network mounts for config directories","Check the chained errno (EACCES, EISDIR) to pick the right fix"],"tags":["rust","filesystem","io","toml"],"backgroundTag":"file-read-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}