googleworkspace/cli · error · anyhow::Error
Failed to set permissions on token directory '{}': {}
Error message
Failed to set permissions on token directory '{}': {} What it means
After creating the token directory, `save_to_disk()` applies `chmod 0700` (unix only) and this call failed. The directory exists and was created, but the OS refused the permission change — typical on filesystems that don't support POSIX mode bits (vfat/exFAT/NTFS mounts, some NFS/CIFS configurations) or when the directory was concurrently replaced by something owned by another user.
Source
Thrown at crates/google-workspace-cli/src/token_storage.rs:98
async fn save_to_disk(&self, map: &HashMap<String, TokenInfo>) -> anyhow::Result<()> {
let json = serde_json::to_string(map)?;
let encrypted = crate::credential_store::encrypt(json.as_bytes())?;
if let Some(parent) = self.file_path.parent() {
tokio::fs::create_dir_all(parent).await.map_err(|e| {
anyhow::anyhow!(
"Failed to create token directory '{}': {}",
sanitize_for_terminal(&parent.display().to_string()),
e
)
})?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
tokio::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700))
.await
.map_err(|e| {
anyhow::anyhow!(
"Failed to set permissions on token directory '{}': {}",
sanitize_for_terminal(&parent.display().to_string()),
e
)
})?;
}
}
// Write atomically via a sibling .tmp file + rename.
crate::fs_util::atomic_write_async(&self.file_path, encrypted.as_slice()).await?;
Ok(())
}
// Helper to join scopes consistently for cache keys
fn cache_key(scopes: &[&str]) -> String {
let mut s: Vec<&str> = scopes.to_vec();
s.sort_unstable();View on GitHub (pinned to a3768d0e82)
Solutions
- Move the config dir to a POSIX filesystem: `GOOGLE_WORKSPACE_CLI_CONFIG_DIR=$HOME/.config/gws` with $HOME on ext4/xfs/apfs.
- On SELinux systems, check for denials (`ausearch -m avc -ts recent`) and adjust the context for the config path.
- Ensure no concurrent gws/auth processes are racing on the same dir; retry the login.
- As a last resort on non-POSIX mounts, accept that mode bits cannot be enforced and use an encrypted-filesystem path instead (the token file is itself AES-GCM encrypted, but directory perms are defense-in-depth).
Example fix
# before — config dir on a Windows mount under WSL export GOOGLE_WORKSPACE_CLI_CONFIG_DIR=/mnt/c/Users/me/gws gws auth login # -> Failed to set permissions on token directory '...': Operation not supported # after — keep secrets on the Linux filesystem export GOOGLE_WORKSPACE_CLI_CONFIG_DIR="$HOME/.config/gws" gws auth login
Defensive patterns
Strategy: try-catch
Validate before calling
// Detect non-POSIX mounts before relying on chmod
fn supports_posix_perms(p: &std::path::Path) -> bool {
use std::os::unix::fs::MetadataExt;
match std::fs::metadata(p) {
Ok(m) => m.mode() & 0o777 != 0 || true, // best-effort: probe with a real chmod instead
Err(_) => false,
}
} Try / catch
if let Err(e) = tokio::fs::set_permissions(parent, perms).await {
// 0700 is defense-in-depth; the token file itself is AES-GCM encrypted.
// Log loudly but do not fail the login on filesystems without POSIX bits.
tracing::warn!(error = %e, dir = %parent.display(), "cannot enforce 0700 on token dir (non-POSIX fs?)");
} Prevention
- Keep GOOGLE_WORKSPACE_CLI_CONFIG_DIR on a native POSIX filesystem (ext4/xfs/apfs), never on FAT/NTFS mounts.
- On SELinux hosts, label the config path correctly before login.
- Avoid concurrent gws auth operations against the same config dir.
When it happens
Trigger: `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` pointed at a FAT/NTFS-mounted USB or Windows-drive mount; an NFS home with root-squash oddities; another process (or admin tool) chowning/replacing the dir between create and chmod; SELinux/AppArmor denying chmod.
Common situations: WSL with config on /mnt/c; mounted external drives; hardened SELinux hosts; shared multi-user systems.
Related errors
- Failed to create token directory '{}': {}
- Failed to write client config: {e}
- Failed to write credentials: {e}
- InvalidInput
- failed to listen for SIGINT
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/c53b850adc151dd6.
Report an issue: GitHub.