{"record":{"id":"55001f148d4e6ae8","repo":"googleworkspace/cli","slug":"encrypted-data-too-short","errorCode":null,"errorMessage":"Encrypted data too short","messagePattern":"Encrypted data too short","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/google-workspace-cli/src/credential_store.rs","lineNumber":402,"sourceCode":"    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]);\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.","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/googleworkspace/cli/blob/a3768d0e82ad83cca2da97724e46bea4ff0e6dbd/crates/google-workspace-cli/src/credential_store.rs#L384-L420","documentation":"decrypt() expects input in nonce||ciphertext layout, so anything shorter than the 12-byte GCM nonce cannot possibly be valid and is rejected before crypto begins. This means the encrypted credentials file exists but is truncated or otherwise not the file format decrypt() produces — typically a 0-byte or near-empty file.","triggerScenarios":"Credentials file truncated to 0 bytes by a crash in a pre-atomic-write version, a full disk, or an overwriting sync tool; a plaintext JSON accidentally saved at the encrypted-credentials path; a placeholder file created by tooling.","commonSituations":"Dropbox/Syncthing sync conflicts zeroing the file; disk-full during an old-version write; manual experimentation with the config dir; restore from a partial backup.","solutions":["Run `gws auth logout` to clear the corrupt file, then `gws auth login` to recreate it","If logout also fails, delete the encrypted credentials file in ~/.config/gws and log in again","Exclude the gws config dir from sync tools, and check disk space"],"exampleFix":"// before: feeding any file straight into decrypt\nlet plaintext = credential_store::decrypt(&std::fs::read(&path)?)?;\n\n// after: sanity-check the minimum viable length (12-byte nonce + 16-byte GCM tag)\nlet data = std::fs::read(&path)?;\nif data.len() < 28 {\n    anyhow::bail!(\"credentials file {} is corrupt ({} bytes) — re-run auth login\", path.display(), data.len());\n}","handlingStrategy":"validation","validationCode":"// Guard before decrypt: nonce(12) + tag(16) is the minimum valid ciphertext\nfn looks_like_ciphertext(data: &[u8]) -> bool {\n    data.len() >= 12 + 16\n}\n\nlet data = std::fs::read(&cred_path)?;\nanyhow::ensure!(looks_like_ciphertext(&data), \"credentials file is corrupt ({} bytes)\", data.len());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep disk space healthy — truncation follows full disks on non-atomic writes","Do not sync the config dir with tools that can leave zero-byte conflict files","After restoring any backup of ~/.config/gws, run `gws auth status` to validate before real work"],"tags":["credentials","corruption","aes-256-gcm","file-format"],"backgroundTag":"corrupt-credentials-file","analyzedSha":"a3768d0e82ad83cca2da97724e46bea4ff0e6dbd","analyzedAt":"2026-08-16T19:51:46.516Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}