{"record":{"id":"c27567fad34bbb8b","repo":"googleworkspace/cli","slug":"decryption-failed-credentials-may-have-been-creat","errorCode":null,"errorMessage":"Decryption failed. Credentials may have been created on a different machine. Run `gws auth logout` and `gws auth login` to re-authenticate.","messagePattern":"Decryption failed\\. Credentials may have been created on a different machine\\. Run `gws auth logout` and `gws auth login` to re-authenticate\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/google-workspace-cli/src/credential_store.rs","lineNumber":411,"sourceCode":"    // Prepend nonce to ciphertext\n    let mut result = nonce.to_vec();\n    result.extend_from_slice(&ciphertext);\n    Ok(result)\n}\n\n/// Decrypts data produced by `encrypt()`.\npub fn decrypt(data: &[u8]) -> anyhow::Result<Vec<u8>> {\n    if data.len() < 12 {\n        anyhow::bail!(\"Encrypted data too short\");\n    }\n\n    let key = get_or_create_key()?;\n    let cipher = Aes256Gcm::new_from_slice(&key)\n        .map_err(|e| anyhow::anyhow!(\"Failed to create cipher: {e}\"))?;\n\n    let nonce = Nonce::from_slice(&data[..12]);\n    let plaintext = cipher.decrypt(nonce, &data[12..]).map_err(|_| {\n        anyhow::anyhow!(\n            \"Decryption failed. Credentials may have been created on a different machine. \\\n                 Run `gws auth logout` and `gws auth login` to re-authenticate.\"\n        )\n    })?;\n\n    Ok(plaintext)\n}\n\n/// Returns the name of the active keyring backend for status display.\npub fn active_backend_name() -> &'static str {\n    KeyringBackend::from_env().as_str()\n}\n\n/// Returns the path for encrypted credentials.\npub fn encrypted_credentials_path() -> PathBuf {\n    crate::auth_commands::config_dir().join(\"credentials.enc\")\n}\n","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/googleworkspace/cli/blob/a3768d0e82ad83cca2da97724e46bea4ff0e6dbd/crates/google-workspace-cli/src/credential_store.rs#L393-L429","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run `gws auth logout && gws auth login` on this machine — the old ciphertext is unreadable by design","If you need portable credentials, use GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE with a plaintext JSON instead of the encrypted store","Never sync or image the gws config dir across machines; treat it as machine-local state"],"exampleFix":"# before: copying state between machines\n$ scp -r oldhost:~/.config/gws ~/.config/gws\n$ gws drive files list   # Decryption failed...\n\n# after: re-authenticate per machine\n$ gws auth logout; gws auth login\n# or ship a plaintext credential file instead:\n$ GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/secrets/sa.json gws drive files list","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match credential_store::decrypt(&data) {\n    Ok(plain) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"different machine\") => {\n        // key mismatch is unrecoverable by design: clear state and re-authenticate\n        let _ = std::fs::remove_file(&cred_path);\n        // prompt: `gws auth login`\n    }\n    Err(e) => { /* corrupt-data or IO paths handled separately */ }\n}","preventionTips":["Never copy ~/.config/gws between machines — the encryption key is machine-bound on purpose","For portable/multi-machine setups use GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE with a plaintext JSON instead","Do not switch GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND on a machine that already has encrypted credentials under the other backend"],"tags":["aes-256-gcm","decryption","credentials","machine-binding","keyring"],"backgroundTag":"aes-gcm-decryption-failed","analyzedSha":"a3768d0e82ad83cca2da97724e46bea4ff0e6dbd","analyzedAt":"2026-08-16T19:51:46.516Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}