{"record":{"id":"b377662aacb12e99","repo":"Hmbown/CodeWhale","slug":"failed-to-write-mcp-config","errorCode":null,"errorMessage":"Failed to write MCP config {}: {}","messagePattern":"Failed to write MCP config (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":10323,"sourceCode":"    valid_name(scope)\n        && valid_name(package)\n        && version.is_none_or(|value| {\n            !value.is_empty()\n                && !value.contains(['@', '/', '\\\\'])\n                && !value.chars().any(char::is_whitespace)\n        })\n}\n\nfn save_mcp_config(path: &Path, cfg: &McpConfig) -> Result<()> {\n    if let Some(parent) = path.parent() {\n        std::fs::create_dir_all(parent).with_context(|| {\n            format!(\"Failed to create MCP config directory {}\", parent.display())\n        })?;\n    }\n    let rendered = serde_json::to_string_pretty(cfg)\n        .map_err(|e| anyhow!(\"Failed to serialize MCP config: {e}\"))?;\n    crate::utils::write_atomic(path, rendered.as_bytes())\n        .map_err(|e| anyhow!(\"Failed to write MCP config {}: {}\", path.display(), e))?;\n    Ok(())\n}\n\nfn run_sandbox_command(args: SandboxArgs) -> Result<()> {\n    use crate::sandbox::{CommandSpec, SandboxManager};\n\n    let SandboxCommand::Run {\n        policy,\n        network,\n        writable_root,\n        exclude_tmpdir,\n        exclude_slash_tmp,\n        cwd,\n        timeout_ms,\n        command,\n    } = args.command;\n\n    let policy = parse_sandbox_policy(","sourceCodeStart":10305,"sourceCodeEnd":10341,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/lib.rs#L10305-L10341","documentation":"Thrown by the MCP config save routine when creating the serialized JSON succeeded but the atomic write to disk failed. The message includes the target path and the underlying error from `crate::utils::write_atomic`.","triggerScenarios":"save_mcp_config when write_atomic fails: no write permission on the file or its directory, directory was removed between create_dir_all and the write, read-only filesystem, disk full, or (for atomic rename semantics) cross-device or lock issues on the target path.","commonSituations":"Config file owned by root after a sudo run; read-only mount or container filesystem; disk quota exceeded; another process holding a conflicting lock; antivirus/backup tools briefly locking the file on Windows.","solutions":["Fix permissions: ensure your user can write the config file and its parent directory.","Free disk space or resolve quota limits if the wrapped error indicates ENOSPC.","Check whether the filesystem/mount is read-only and remount or choose another --config-path.","Recreate a root-owned config as your user (`sudo chown $USER <path>`)."],"exampleFix":"// before\nsudo codewhale mcp enable my-server   # may leave root-owned config\n// after\ncodewhale mcp enable my-server\n# or repair once: sudo chown $USER: $(path to mcp.json)","handlingStrategy":"try-catch","validationCode":"let probe = path.with_extension(\".probe\");\nif std::fs::write(&probe, b\"\").is_err() {\n    eprintln!(\"no write access to config directory: {}\", path.display());\n}\nlet _ = std::fs::remove_file(&probe);","typeGuard":null,"tryCatchPattern":"match std::fs::write(&path, &rendered) {\n    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => eprintln!(\"chown/chmod the config: {}\", path.display()),\n    Err(e) => eprintln!(\"write failed: {e}\"),\n    Ok(_) => /* continue */,\n}","preventionTips":["Check free disk space and quota before bulk config changes.","Avoid sudo for MCP commands so the config stays user-owned.","Confirm the target filesystem is writable (not a read-only mount)."],"tags":["filesystem","mcp","config","write"],"backgroundTag":"file-write-failed","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}