googleworkspace/cli · error · anyhow::Error

Failed to create token directory '{}': {}

Error message

Failed to create token directory '{}': {}

What it means

`FileTokenStorage::save_to_disk()` failed at `tokio::fs::create_dir_all(parent)` for the token-cache directory (the parent of the encrypted token file under the gws config dir). The message includes the sanitized directory path and OS error. The token map is encrypted and written via atomic rename immediately after, so this is a pure filesystem/permissions problem on the directory path.

Source

Thrown at crates/google-workspace-cli/src/token_storage.rs:86

        match serde_json::from_str(&json) {
            Ok(map) => map,
            Err(e) => {
                eprintln!(
                    "warning: failed to parse token cache JSON: {}",
                    sanitize_for_terminal(&e.to_string())
                );
                HashMap::new()
            }
        }
    }

    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
                        )
                    })?;
            }

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Ensure HOME is set (or CONFIG_DIR exported) in the environment the command runs in — `runuser -u me -- env HOME=/home/me gws auth login`.
  2. mkdir -p the path shown in the error by hand and fix ownership/permissions (0700, your uid).
  3. Remove any *file* occupying the directory path (ENOTDIR shows as 'Not a directory').
  4. In containers, mount a writable volume at the config dir or point CONFIG_DIR at /tmp-based storage for ephemeral auth.

Example fix

# before — service context, HOME unset
[Unit] Service: ExecStart=/usr/bin/gws gmail +standup-report
# -> Failed to create token directory '/.config/gws/tokens': Permission denied

# after — explicit writable config dir
[Service]
Environment=HOME=/var/lib/gws
# or: Environment=GOOGLE_WORKSPACE_CLI_CONFIG_DIR=/var/lib/gws/config
ExecStart=/usr/bin/gws gmail +standup-report
Defensive patterns

Strategy: validation

Validate before calling

// Prove the token dir can be created/used before login
async fn token_dir_ok(dir: &std::path::Path) -> bool {
    tokio::fs::create_dir_all(dir).await.is_ok()
        && tokio::fs::write(dir.join(".probe"), b"").await.is_ok()
        && tokio::fs::remove_file(dir.join(".probe")).await.is_ok()
}

Try / catch

if let Err(e) = storage.save(&map).await {
    if e.to_string().contains("Failed to create token directory") {
        eprintln!("cannot create {} — check HOME/GOOGLE_WORKSPACE_CLI_CONFIG_DIR and permissions", e);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: `gws auth login` when the config dir (default `~/.config/gws`, overridable via `GOOGLE_WORKSPACE_CLI_CONFIG_DIR`) cannot be created: parent is read-only, HOME unset in a service context, path collides with an existing *file*, or sandbox/seatbelt denies writes outside allowed paths.

Common situations: Running gws under systemd/launchd without HOME set; macOS Gatekeeper/sandboxed execution; CONFIG_DIR pointing into a read-only container volume; a leftover file named like the directory.

Related errors


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