googleworkspace/cli · error

Failed to write credentials: {e}

Error message

Failed to write credentials: {e}

What it means

The final persistence step in save: after encrypting the JSON, the bytes are written via atomic_write (sibling .tmp + rename). This error wraps any failure of that write — permission denied on the config dir, read-only filesystem, disk full, or the target path being unusable. The atomic strategy means the previous credentials file is never left half-written by these failures.

Source

Thrown at crates/google-workspace-cli/src/credential_store.rs:453

        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            if let Err(e) = std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700))
            {
                eprintln!(
                    "Warning: failed to set directory permissions on {}: {e}",
                    parent.display()
                );
            }
        }
    }

    let encrypted = encrypt(json.as_bytes())?;

    // Write atomically via a sibling .tmp file + rename so the credentials
    // file is never left in a corrupt partial-write state on crash/Ctrl-C.
    crate::fs_util::atomic_write(&path, &encrypted)
        .map_err(|e| anyhow::anyhow!("Failed to write credentials: {e}"))?;

    Ok(path)
}

/// Loads and decrypts credentials JSON from a specific path.
pub fn load_encrypted_from_path(path: &std::path::Path) -> anyhow::Result<String> {
    let data = std::fs::read(path)?;
    let plaintext = decrypt(&data)?;
    Ok(String::from_utf8(plaintext)?)
}

/// Loads and decrypts credentials JSON from the default encrypted file.
pub fn load_encrypted() -> anyhow::Result<String> {
    load_encrypted_from_path(&encrypted_credentials_path())
}

#[cfg(test)]
mod tests {

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Check ownership: `ls -ld ~/.config/gws` and fix with chown if it is owned by root
  2. Verify writability: `touch ~/.config/gws/.probe` (or your GOOGLE_WORKSPACE_CLI_CONFIG_DIR) and check disk space with `df -h`
  3. Point GOOGLE_WORKSPACE_CLI_CONFIG_DIR at a writable directory, or fix the mount options / SELinux policy

Example fix

# before
$ sudo gws auth login   # creates root-owned ~/.config/gws
$ gws auth login         # Failed to write credentials

# after
$ sudo chown -R "$USER:$USER" ~/.config/gws
$ gws auth login
Defensive patterns

Strategy: validation

Validate before calling

// Preflight: prove the config dir is writable before login
use std::io::Write;

fn config_dir_writable(dir: &std::path::Path) -> bool {
    std::fs::create_dir_all(dir).is_ok() && {
        let probe = dir.join(".write_probe");
        std::fs::File::create(&probe).and_then(|mut f| f.write_all(b"x")).is_ok()
            && std::fs::remove_file(&probe).is_ok()
    }
}

Prevention

When it happens

Trigger: ~/.config/gws owned by root after running gws with sudo; GOOGLE_WORKSPACE_CLI_CONFIG_DIR pointing at a read-only mount; disk quota exhausted; directory in the path replaced by a file; SELinux denying writes.

Common situations: Ran `sudo gws auth login` once, then normal user cannot write; container with a read-only config mount; CI runner with a full disk; config dir on a hardened NFS mount.

Related errors


AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16). Data as JSON: /api/errors/9d01d7053102770e. Report an issue: GitHub.