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

  1. Ensure the recipient has a valid OpenPGP key and their fingerprint is set before encrypting (call setEncryptKey).
  2. Guard with a fingerprint check before attempting encryption, and skip or handle users without keys.
  3. 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

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


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)