passbolt/passbolt_api · error · Cake\Core\Exception\CakeException
Can not encrypt without a key. Set a public key first.
Error message
Can not encrypt without a key. Set a public key first.
What it means
assertEncryptKey() is a precondition check for OpenPGP encryption in OpenPGPCommonAssertsTrait. It throws a CakeException when _encryptKeyFingerprint is empty, because a public key of the recipient must be set (via setEncryptKey) before encrypting data.
Solutions
- Ensure the recipient has a valid OpenPGP key and their fingerprint is set before encrypting (call setEncryptKey).
- Guard with a fingerprint check before attempting encryption, and skip or handle users without keys.
- Import the recipient public key into the keyring if it is missing (though that alone does not fix the empty fingerprint).
Example fix
// before
$encrypted = $gpg->encrypt($secret); // throws: no encrypt key
// after
if (!empty($user->gpgkey->fingerprint)) {
$gpg->setEncryptKey($user->gpgkey->fingerprint);
$encrypted = $gpg->encrypt($secret);
} Defensive patterns
Strategy: validation
Validate before calling
if (empty($user->gpgkey?->fingerprint)) {
throw new BadRequestException('User has no OpenPGP key; cannot encrypt.');
}
$gpg->setEncryptKey($user->gpgkey->fingerprint); Type guard
function isEncryptable(?Gpgkey $key): bool {
return $key !== null && !empty($key->fingerprint) && $key->deleted === false;
} Try / catch
try {
$cipher = $gpg->encrypt($secret);
} catch (\Cake\Core\Exception\CakeException $e) {
if (str_contains($e->getMessage(), 'encrypt without a key')) {
// recipient has no key: skip and report per-user failure
return null;
}
throw $e;
} Prevention
- Require a valid OpenPGP key at user onboarding before allowing secret sharing.
- Filter recipient lists to users with keys before batch encryption.
- Validate fingerprint presence in the service layer, not just at encryption time.
When it happens
Trigger: Calling encrypt() (or paths that invoke assertEncryptKey) without a prior setEncryptKey() call, or with an empty recipient fingerprint — e.g. encrypting a secret for a user whose key fingerprint was not resolved/stored.
Common situations: Sharing a secret with a user who has no OpenPGP key yet (fingerprint column empty in DB), user deleted key but records still reference them, new encryption code path missing key setup, batch jobs encrypting for many users where one lacks a key.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- No OpenPGP key found for the user. The metadata could not…
- Can not decrypt without a key. Set a secret key first.
- Can not sign without a key. Set a sign key first.
- Can not verify without a key. Set a verification key first.
- Could not use the key to encrypt.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/6d8ea2bf87629c8a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php:94
* @return void
*/
public function assertVerifyKey(): void
{
if (empty($this->_verifyKeyFingerprint)) {
throw new CakeException('Can not verify without a key. Set a verification key first.');
}
}
/**
* Check if an encryption key is set
*
* @throws \Cake\Core\Exception\CakeException if no encryption key is set
* @return void
*/
public function assertEncryptKey(): void
{
if (empty($this->_encryptKeyFingerprint)) {
throw new CakeException('Can not encrypt without a key. Set a public key first.');
}
}
/**
* Check if a decrypt key is set
*
* @throws \Cake\Core\Exception\CakeException if no decryption key is set
* @return void
*/
public function assertDecryptKey(): void
{
if (empty($this->_decryptKeyFingerprint)) {
throw new CakeException('Can not decrypt without a key. Set a secret key first.');
}
}
}
View on GitHub (pinned to 31c1bbc10f)