googleworkspace/cli · error

Decryption failed. Credentials may have been created on a di

Error message

Decryption failed. Credentials may have been created on a different machine. Run `gws auth logout` and `gws auth login` to re-authenticate.

What it means

AES-256-GCM authentication failed: the ciphertext's auth tag does not verify under the current key. Because the key is machine-bound (OS keyring or key file), the classic cause is decrypting credentials that were encrypted under a different key — another machine, a reset keyring, or a reinstalled OS. The message deliberately tells the user the recovery path: logout and login again.

Source

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

    // Prepend nonce to ciphertext
    let mut result = nonce.to_vec();
    result.extend_from_slice(&ciphertext);
    Ok(result)
}

/// Decrypts data produced by `encrypt()`.
pub fn decrypt(data: &[u8]) -> anyhow::Result<Vec<u8>> {
    if data.len() < 12 {
        anyhow::bail!("Encrypted data too short");
    }

    let key = get_or_create_key()?;
    let cipher = Aes256Gcm::new_from_slice(&key)
        .map_err(|e| anyhow::anyhow!("Failed to create cipher: {e}"))?;

    let nonce = Nonce::from_slice(&data[..12]);
    let plaintext = cipher.decrypt(nonce, &data[12..]).map_err(|_| {
        anyhow::anyhow!(
            "Decryption failed. Credentials may have been created on a different machine. \
                 Run `gws auth logout` and `gws auth login` to re-authenticate."
        )
    })?;

    Ok(plaintext)
}

/// Returns the name of the active keyring backend for status display.
pub fn active_backend_name() -> &'static str {
    KeyringBackend::from_env().as_str()
}

/// Returns the path for encrypted credentials.
pub fn encrypted_credentials_path() -> PathBuf {
    crate::auth_commands::config_dir().join("credentials.enc")
}

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Run `gws auth logout && gws auth login` on this machine — the old ciphertext is unreadable by design
  2. If you need portable credentials, use GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE with a plaintext JSON instead of the encrypted store
  3. Never sync or image the gws config dir across machines; treat it as machine-local state

Example fix

# before: copying state between machines
$ scp -r oldhost:~/.config/gws ~/.config/gws
$ gws drive files list   # Decryption failed...

# after: re-authenticate per machine
$ gws auth logout; gws auth login
# or ship a plaintext credential file instead:
$ GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/secrets/sa.json gws drive files list
Defensive patterns

Strategy: fallback

Try / catch

match credential_store::decrypt(&data) {
    Ok(plain) => { /* proceed */ }
    Err(e) if e.to_string().contains("different machine") => {
        // key mismatch is unrecoverable by design: clear state and re-authenticate
        let _ = std::fs::remove_file(&cred_path);
        // prompt: `gws auth login`
    }
    Err(e) => { /* corrupt-data or IO paths handled separately */ }
}

Prevention

When it happens

Trigger: Copying ~/.config/gws between machines or containers (key does not travel with it); OS keyring wiped/re-created (new random key generated); GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND switched between keyring and file backends (different key domains); key file deleted and regenerated while old encrypted credentials remain.

Common situations: Baking a config dir into a Docker image; syncing config across machines; Linux re-install; headless machine where the file backend key was removed; CI caching ~/.config/gws.

Understand the failure class

Related errors


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