passbolt/passbolt_api · error · Cake\Core\Exception\CakeException

Can not decrypt without a key. Set a secret key first.

Error message

Can not decrypt without a key. Set a secret key first.

What it means

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.

Solutions

  1. Call setDecryptKey() with the server secret key fingerprint (and passphrase if protected) before decrypting.
  2. Verify the server private key is configured (config values/env) and the bootstrap that loads it runs in the failing context.
  3. Confirm the secret key is present in the keyring and readable by the process user.

Example fix

// before
$plain = $gpg->decrypt($cipher); // throws: no decrypt key
// after
$gpg->setDecryptKey($serverKeyFingerprint, $serverKeyPassphrase);
$plain = $gpg->decrypt($cipher);
Defensive patterns

Strategy: type-guard

Validate before calling

if (empty($serverKeyFingerprint)) {
    throw new \RuntimeException('Server decrypt key is not configured.');
}
$gpg->setDecryptKey($serverKeyFingerprint, $passphrase);

Type guard

function canDecrypt($gpg): bool {
    return isset($gpg) && !empty($gpg->getDecryptKeyFingerprint());
}

Try / catch

try {
    $plain = $gpg->decrypt($cipher);
} catch (\Cake\Core\Exception\CakeException $e) {
    if (str_contains($e->getMessage(), 'decrypt without a key')) {
        // server key not loaded: fail loudly with a config-level message
        throw new \RuntimeException('Server key not loaded into OpenPGP utility.', 0, $e);
    }
    throw $e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/dd7944f28fe8ced9. Report an issue: GitHub.

Appendix: source

Thrown at src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php:107

     * @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)