googleworkspace/cli · error · anyhow::Error
Failed to write client config: {e}
Error message
Failed to write client config: {e} What it means
`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.
Source
Thrown at crates/google-workspace-cli/src/oauth_config.rs:85
installed: InstalledConfig {
client_id: client_id.to_string(),
client_secret: client_secret.to_string(),
project_id: project_id.to_string(),
auth_uri: "https://accounts.google.com/o/oauth2/auth".to_string(),
token_uri: "https://oauth2.googleapis.com/token".to_string(),
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs".to_string(),
redirect_uris: vec!["http://localhost".to_string()],
},
};
let path = client_config_path();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let json = serde_json::to_string_pretty(&config)?;
crate::fs_util::atomic_write(&path, json.as_bytes())
.map_err(|e| anyhow::anyhow!("Failed to write client config: {e}"))?;
Ok(path)
}
/// Loads OAuth client configuration from the standard Google Cloud Console format.
pub fn load_client_config() -> anyhow::Result<InstalledConfig> {
let path = client_config_path();
let data = std::fs::read_to_string(&path)
.map_err(|e| anyhow::anyhow!("Cannot read {}: {e}", path.display()))?;
let file: ClientSecretFile = serde_json::from_str(&data)
.map_err(|e| anyhow::anyhow!("Invalid client_secret.json format: {e}"))?;
Ok(file.installed)
}
#[cfg(test)]
mod tests {
use super::*;
View on GitHub (pinned to a3768d0e82)
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.
Example fix
# before GOOGLE_WORKSPACE_CLI_CONFIG_DIR=/etc/gws gws auth login # -> Failed to write client config: ... Permission denied # after — point at a writable dir (or fix ownership of the default) export GOOGLE_WORKSPACE_CLI_CONFIG_DIR="$HOME/.config/gws" chown -R "$(id -u):$(id -g)" "$HOME/.config/gws" gws auth login
Defensive patterns
Strategy: validation
Validate before calling
// Prove the config dir is writable before starting auth
fn config_dir_writable(dir: &std::path::Path) -> bool {
std::fs::create_dir_all(dir).is_ok()
&& std::fs::write(dir.join(".probe"), b"").is_ok()
&& std::fs::remove_file(dir.join(".probe")).is_ok()
} Try / catch
if let Err(e) = gws_oauth_config::save_client_config(id, secret, project) {
if e.to_string().contains("Failed to write client config") {
eprintln!("config dir not writable — set GOOGLE_WORKSPACE_CLI_CONFIG_DIR to a writable path");
}
return Err(e);
} Prevention
- 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.
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- Failed to create token directory '{}': {}
- Token refresh failed with status {}: {}
- Token response contained no access token
- Cannot read {}: {e}
- Invalid client_secret.json format: {e}
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/2ee7873653e0f1b4.
Report an issue: GitHub.