{"record":{"id":"2ee7873653e0f1b4","repo":"googleworkspace/cli","slug":"failed-to-write-client-config-e","errorCode":null,"errorMessage":"Failed to write client config: {e}","messagePattern":"Failed to write client config: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/google-workspace-cli/src/oauth_config.rs","lineNumber":85,"sourceCode":"        installed: InstalledConfig {\n            client_id: client_id.to_string(),\n            client_secret: client_secret.to_string(),\n            project_id: project_id.to_string(),\n            auth_uri: \"https://accounts.google.com/o/oauth2/auth\".to_string(),\n            token_uri: \"https://oauth2.googleapis.com/token\".to_string(),\n            auth_provider_x509_cert_url: \"https://www.googleapis.com/oauth2/v1/certs\".to_string(),\n            redirect_uris: vec![\"http://localhost\".to_string()],\n        },\n    };\n\n    let path = client_config_path();\n    if let Some(parent) = path.parent() {\n        std::fs::create_dir_all(parent)?;\n    }\n\n    let json = serde_json::to_string_pretty(&config)?;\n    crate::fs_util::atomic_write(&path, json.as_bytes())\n        .map_err(|e| anyhow::anyhow!(\"Failed to write client config: {e}\"))?;\n\n    Ok(path)\n}\n\n/// Loads OAuth client configuration from the standard Google Cloud Console format.\npub fn load_client_config() -> anyhow::Result<InstalledConfig> {\n    let path = client_config_path();\n    let data = std::fs::read_to_string(&path)\n        .map_err(|e| anyhow::anyhow!(\"Cannot read {}: {e}\", path.display()))?;\n    let file: ClientSecretFile = serde_json::from_str(&data)\n        .map_err(|e| anyhow::anyhow!(\"Invalid client_secret.json format: {e}\"))?;\n    Ok(file.installed)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/googleworkspace/cli/blob/a3768d0e82ad83cca2da97724e46bea4ff0e6dbd/crates/google-workspace-cli/src/oauth_config.rs#L67-L103","documentation":"`save_client_config()` could not persist the OAuth client_secret JSON to `<config dir>/client_secret.json`: the atomic write (sibling temp file + rename via `fs_util::atomic_write`) returned an OS error, wrapped with this message. The parent directory is created first, so the failure is almost always a filesystem-level problem with the config directory itself, not a missing path.","triggerScenarios":"`gws auth login` / `gws auth setup` when `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` points somewhere unwritable (a root-owned dir, a read-only mount); the default `~/.config/gws` being read-only (chmod 500); disk full; an immutable-file attribute (chattr +i) on the file.","commonSituations":"Running as a different user than the one that owns ~/.config; Docker containers with read-only volumes mounted at the config dir; home directory quota exhausted; sudo/root-owned ~/.config/gws from a previous run.","solutions":["Check writability: `touch ~/.config/gws/.probe` (or your CONFIG_DIR) — fix ownership with `chown -R $USER ~/.config/gws` if root-owned.","If intentional, point `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` to a writable directory and re-run the auth command.","Free disk space / raise quota if the write failed with ENOSPC.","Remove immutable attributes (`chattr -i`) or read-only mounts on the config dir."],"exampleFix":"# before\nGOOGLE_WORKSPACE_CLI_CONFIG_DIR=/etc/gws gws auth login\n# -> Failed to write client config: ... Permission denied\n\n# after — point at a writable dir (or fix ownership of the default)\nexport GOOGLE_WORKSPACE_CLI_CONFIG_DIR=\"$HOME/.config/gws\"\nchown -R \"$(id -u):$(id -g)\" \"$HOME/.config/gws\"\ngws auth login","handlingStrategy":"validation","validationCode":"// Prove the config dir is writable before starting auth\nfn config_dir_writable(dir: &std::path::Path) -> bool {\n    std::fs::create_dir_all(dir).is_ok()\n        && std::fs::write(dir.join(\".probe\"), b\"\").is_ok()\n        && std::fs::remove_file(dir.join(\".probe\")).is_ok()\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = gws_oauth_config::save_client_config(id, secret, project) {\n    if e.to_string().contains(\"Failed to write client config\") {\n        eprintln!(\"config dir not writable — set GOOGLE_WORKSPACE_CLI_CONFIG_DIR to a writable path\");\n    }\n    return Err(e);\n}","preventionTips":["Run `gws auth setup` as the same user that will run gws commands, so ownership of ~/.config/gws stays consistent.","In containers/CI, always set GOOGLE_WORKSPACE_CLI_CONFIG_DIR to a mounted writable volume.","Include a writable-config-dir probe in environment bootstrap scripts."],"tags":["oauth","filesystem","config","permissions","auth"],"backgroundTag":"file-write-permission-denied","analyzedSha":"a3768d0e82ad83cca2da97724e46bea4ff0e6dbd","analyzedAt":"2026-08-16T19:51:46.516Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}