passbolt/passbolt_api · error · CakeException
The key cannot be used to encrypt.
Error message
The key {0} cannot be used to encrypt. What it means
setEncryptKey() parses an armored public key, extracts its fingerprint, and asks gnupg->addencryptkey() to register it. If that fails, it imports the key into the keyring and retries; if the retry also throws, it wraps the gnupg error in a CakeException 'The key {0} cannot be used to encrypt.' plus the underlying gnupg message. This means GnuPG could not select the key for encryption even after importing it.
Solutions
- Read the appended $e->getMessage() to see gnupg's actual cause, and check that passbolt.gpg.keyring exists, is owned by the web server user, and has correct permissions (700 dir owned by www-data/http).
- Verify the key has a usable encryption subkey: gpg --list-packets on the armored key or `gpg --import` manually then `gpg --list-keys --with-subkey-fingerprints`; regenerate/re-export a key with encryption capability if missing.
- Import the key manually as the web user (sudo -u www-data gpg --import key.asc) to see the raw gpg error, then fix accordingly (corrupt armor, unsupported algorithm, expired key).
- If the key is expired or its encryption subkey revoked, the owner must generate/extend the key and re-upload it before encryption can proceed.
Example fix
# before: keyring dir owned by root sudo chown -R www-data:www-data /var/lib/passbolt/.gnupg sudo chmod 700 /var/lib/passbolt/.gnupg # after: retry; if still failing, inspect key subkeys gpg --list-packets user_public.asc | grep -A2 'key *alg' # ensure a subkey with 'Encr' capability exists
Defensive patterns
Strategy: try-catch
Validate before calling
use App\Utility\OpenPGP\Backends\Gnupg;
$gpg = new Gnupg();
$keyInfo = $gpg->getPublicKeyInfo($armoredKey); // throws early if armor is unparsable
$fpr = $keyInfo['fingerprint'];
if (!$gpg->isKeyInKeyring($fpr)) {
$gpg->importKeyIntoKeyring($armoredKey); // surface import errors before addencryptkey
}
Try / catch
try {
$gpg->setEncryptKey($armoredKey);
} catch (\Cake\Core\Exception\CakeException $e) {
// $e->getMessage() contains the gnupg cause; check keyring perms and key subkeys
$this->log('Encryption key setup failed: ' . $e->getMessage());
throw new UserEncryptionKeyException('Recipient key unusable for encryption.');
}
Prevention
- Keep passbolt.gpg.keyring owned by the web server user with 700 permissions.
- Validate user-uploaded keys for an encryption-capable, unexpired subkey at registration/upload time.
- Test key import manually with sudo -u www-data gpg --import to catch environment issues early.
- Pin and update gpg/gpgme versions; very old gpg builds can reject modern key algorithms.
When it happens
Trigger: Calling setEncryptKey($armoredKey) when the keyring path (GNUPGHOME) is not writable by the web server user (import silently/exception fails), the armored key is corrupt or contains no usable encryption subkey (e.g. key with encryption capability revoked/removed, or a sign-only key), or the fingerprint from the parsed key does not match anything gpg can add.
Common situations: passbolt.gpg.keyring pointing to a directory not owned by www-data/http so imports fail; server keys imported into root's keyring instead of the web user's; user keys generated without an encryption-capable subkey; gpg agent errors or an outdated gpg binary producing gnupg exceptions on addencryptkey.
Related errors
- Could not import the user OpenPGP key.
- Could not use the key to encrypt.
- The metadata could not be encrypted with the metadata key id
- 500
- 500
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/30d0bb4d1745d598.
Report an issue: GitHub.
Appendix: source
Thrown at src/Utility/OpenPGP/Backends/Gnupg.php:95
{
$this->_encryptKeyFingerprint = null;
// Get the key info.
$encryptKeyInfo = $this->getPublicKeyInfo($armoredKey);
$fingerprint = $encryptKeyInfo['fingerprint'];
try {
$this->_gpg->addencryptkey($fingerprint);
$this->_encryptKeyFingerprint = $fingerprint;
} catch (Exception $e) {
// It didn't work, maybe only key is not in the keyring
// we import the key and retry
$this->importKeyIntoKeyring($armoredKey);
try {
$this->_gpg->addencryptkey($fingerprint);
$this->_encryptKeyFingerprint = $fingerprint;
} catch (Exception $e) {
$msg = __('The key {0} cannot be used to encrypt.', $fingerprint) . ' ' . $e->getMessage();
throw new CakeException($msg, null, $e);
}
}
return true;
}
/**
* Set a key for encryption.
*
* @param string $fingerprint fingerprint
* @throws \Cake\Core\Exception\CakeException if key is not present in keyring or there was an issue to use the key to encrypt
* @return bool true if success
*/
public function setEncryptKeyFromFingerprint(string $fingerprint): bool
{
$this->_encryptKeyFingerprint = null;
$this->assertKeyInKeyring($fingerprint);
try {View on GitHub (pinned to 31c1bbc10f)