{"record":{"id":"83a51ad140128c3c","repo":"googleworkspace/cli","slug":"encryption-failed-e","errorCode":null,"errorMessage":"Encryption failed: {e}","messagePattern":"Encryption failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/google-workspace-cli/src/credential_store.rs","lineNumber":391,"sourceCode":"        Ok(key)\n    } else {\n        Ok(*KEY\n            .get()\n            .expect(\"key must be initialized if OnceLock::set() failed\"))\n    }\n}\n\n/// Encrypts plaintext bytes using AES-256-GCM with a machine-derived key.\n/// Returns nonce (12 bytes) || ciphertext.\npub fn encrypt(plaintext: &[u8]) -> anyhow::Result<Vec<u8>> {\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 = Aes256Gcm::generate_nonce(&mut OsRng);\n    let ciphertext = cipher\n        .encrypt(&nonce, plaintext)\n        .map_err(|e| anyhow::anyhow!(\"Encryption failed: {e}\"))?;\n\n    // 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]);","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/googleworkspace/cli/blob/a3768d0e82ad83cca2da97724e46bea4ff0e6dbd/crates/google-workspace-cli/src/credential_store.rs#L373-L409","documentation":"cipher.encrypt() in encrypt() fails only when the AES-GCM AEAD cannot process the input — in practice only when the plaintext exceeds the AEAD's maximum message size (roughly 64 GiB for GCM). Credential JSON is a few KiB, so this is a defensive branch that guards against absurd inputs rather than an expected failure mode.","triggerScenarios":"Passing a multi-gigabyte 'credential' payload into the credential store; memory exhaustion. Ordinary credential files never trigger it.","commonSituations":"Accidentally pointing the credential store at a huge file during custom tooling; otherwise not observed in the wild.","solutions":["Verify the plaintext being stored is a real credentials JSON of sane size","Report a bug if the payload is a normal credential file"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep stored payloads as small credential JSON — never feed arbitrary large blobs into the credential store","Treat an 'Encryption failed' on a normal-size payload as a bug worth reporting"],"tags":["aes-256-gcm","crypto","invariant","defensive"],"backgroundTag":"aes-gcm-encryption-failed","analyzedSha":"a3768d0e82ad83cca2da97724e46bea4ff0e6dbd","analyzedAt":"2026-08-16T19:51:46.516Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}