{"record":{"id":"dd7944f28fe8ced9","repo":"passbolt/passbolt_api","slug":"can-not-decrypt-without-a-key-set-a-secret-key-first","errorCode":null,"errorMessage":"Can not decrypt without a key. Set a secret key first.","messagePattern":"Can not decrypt without a key\\. Set a secret key first\\.","errorType":"exception","errorClass":"Cake\\Core\\Exception\\CakeException","httpStatus":null,"severity":"error","filePath":"src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php","lineNumber":107,"sourceCode":"     * @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":89,"sourceCodeEnd":111,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php#L89-L111","documentation":"assertDecryptKey() is a precondition check for OpenPGP decryption in OpenPGPCommonAssertsTrait. It throws a CakeException when _decryptKeyFingerprint is empty, because the server's private (secret) key must be set via setDecryptKey() before any ciphertext can be decrypted.","triggerScenarios":"Calling decrypt() (or code invoking assertDecryptKey) without setDecryptKey() having been called — e.g. a CLI command or service that builds an OpenPGP utility instance without loading the server's private key fingerprint.","commonSituations":"Server key not configured in environment/config so bootstrap skips setDecryptKey; running recovery/CLI scripts outside the web bootstrap; key rotation leaving decrypt key unset while data still encrypted with the old key.","solutions":["Call setDecryptKey() with the server secret key fingerprint (and passphrase if protected) before decrypting.","Verify the server private key is configured (config values/env) and the bootstrap that loads it runs in the failing context.","Confirm the secret key is present in the keyring and readable by the process user."],"exampleFix":"// before\n$plain = $gpg->decrypt($cipher); // throws: no decrypt key\n// after\n$gpg->setDecryptKey($serverKeyFingerprint, $serverKeyPassphrase);\n$plain = $gpg->decrypt($cipher);","handlingStrategy":"type-guard","validationCode":"if (empty($serverKeyFingerprint)) {\n    throw new \\RuntimeException('Server decrypt key is not configured.');\n}\n$gpg->setDecryptKey($serverKeyFingerprint, $passphrase);","typeGuard":"function canDecrypt($gpg): bool {\n    return isset($gpg) && !empty($gpg->getDecryptKeyFingerprint());\n}","tryCatchPattern":"try {\n    $plain = $gpg->decrypt($cipher);\n} catch (\\Cake\\Core\\Exception\\CakeException $e) {\n    if (str_contains($e->getMessage(), 'decrypt without a key')) {\n        // server key not loaded: fail loudly with a config-level message\n        throw new \\RuntimeException('Server key not loaded into OpenPGP utility.', 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Load the server secret key in a shared bootstrap used by both web and CLI contexts.","Add a startup check that the server key fingerprint config is present and the key is in the keyring.","Document key setup as a prerequisite for any command that decrypts data."],"tags":["openpgp","decryption","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"}