{"record":{"id":"6d8ea2bf87629c8a","repo":"passbolt/passbolt_api","slug":"can-not-encrypt-without-a-key-set-a-public-key-first","errorCode":null,"errorMessage":"Can not encrypt without a key. Set a public key first.","messagePattern":"Can not encrypt without a key\\. Set a public key first\\.","errorType":"exception","errorClass":"Cake\\Core\\Exception\\CakeException","httpStatus":null,"severity":"error","filePath":"src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php","lineNumber":94,"sourceCode":"     * @return void\n     */\n    public function assertVerifyKey(): void\n    {\n        if (empty($this->_verifyKeyFingerprint)) {\n            throw new CakeException('Can not verify without a key. Set a verification key first.');\n        }\n    }\n\n    /**\n     * Check if an encryption key is set\n     *\n     * @throws \\Cake\\Core\\Exception\\CakeException if no encryption key is set\n     * @return void\n     */\n    public function assertEncryptKey(): void\n    {\n        if (empty($this->_encryptKeyFingerprint)) {\n            throw new CakeException('Can not encrypt without a key. Set a public key first.');\n        }\n    }\n\n    /**\n     * Check if a decrypt key is set\n     *\n     * @throws \\Cake\\Core\\Exception\\CakeException if no decryption key is set\n     * @return void\n     */\n    public function assertDecryptKey(): void\n    {\n        if (empty($this->_decryptKeyFingerprint)) {\n            throw new CakeException('Can not decrypt without a key. Set a secret key first.');\n        }\n    }\n}\n","sourceCodeStart":76,"sourceCodeEnd":111,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php#L76-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\n$encrypted = $gpg->encrypt($secret); // throws: no encrypt key\n// after\nif (!empty($user->gpgkey->fingerprint)) {\n    $gpg->setEncryptKey($user->gpgkey->fingerprint);\n    $encrypted = $gpg->encrypt($secret);\n}","handlingStrategy":"validation","validationCode":"if (empty($user->gpgkey?->fingerprint)) {\n    throw new BadRequestException('User has no OpenPGP key; cannot encrypt.');\n}\n$gpg->setEncryptKey($user->gpgkey->fingerprint);","typeGuard":"function isEncryptable(?Gpgkey $key): bool {\n    return $key !== null && !empty($key->fingerprint) && $key->deleted === false;\n}","tryCatchPattern":"try {\n    $cipher = $gpg->encrypt($secret);\n} catch (\\Cake\\Core\\Exception\\CakeException $e) {\n    if (str_contains($e->getMessage(), 'encrypt without a key')) {\n        // recipient has no key: skip and report per-user failure\n        return null;\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["openpgp","encryption","missing-key"],"backgroundTag":"empty-required-field","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}