passbolt/passbolt_api · error · BadRequestException
The subscription key cannot be verified.
Error message
The subscription key cannot be verified.
What it means
SubscriptionKeySaveService::save threw SubscriptionSignatureException, meaning the submitted subscription key's cryptographic signature failed verification — the key is invalid, corrupted, or not a genuine passbolt-issued license. The controller surfaces it as a 400 with this message.
Solutions
- Re-copy the subscription key exactly as delivered, including the full PGP MESSAGE armor blocks
- Re-download the key from the passbolt customer portal
- Confirm the key matches your subscription/organization ID and is for the passbolt product
- Contact passbolt support if a freshly issued key still fails signature verification
Example fix
// before data=-----BEGIN PGP MESSAGE----- ...truncated block... // after data=-----BEGIN PGP MESSAGE----- <full, unmodified armored subscription key> -----END PGP MESSAGE-----
Defensive patterns
Strategy: validation
Validate before calling
const key = fs.readFileSync('subscription_key.txt', 'utf8').trim();
if (!key.startsWith('-----BEGIN PGP MESSAGE-----') || !key.endsWith('-----END PGP MESSAGE-----')) {
throw new Error('Subscription key armor incomplete — re-copy the full key');
} Try / catch
const res = await saveKey(key);
if (res.status === 400 && res.body.message.includes('cannot be verified')) {
console.error('Key signature invalid: re-download the key and retry without editing it');
} Prevention
- Never hand-edit the armored key text
- Disable line re-wrapping in the client used to copy the key
- Keep the original email/portal copy as the single source of truth
When it happens
Trigger: POST/PUT /subscription.jsonapi where the key text was truncated, line-wrapped/altered in transit, hand-edited, or simply not a valid passbolt subscription key.
Common situations: Copy/paste losing PGP message lines; email client re-wrapping the armored key; pasting a key for a different product or customer; attempting to forge/modify an existing key.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- $e->getMessage() (from SubscriptionSignatureException)
- The subscription key cannot be verified.
- Subscription key data is required.
- A Duo state cookie is required.
- A Duo state cookie is required.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/f777734ebd1d1b4e.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Subscription/src/Controller/Subscriptions/SubscriptionsUpdateController.php:49
{
/**
* @return void
*/
public function update(): void
{
if (!$this->User->isAdmin()) {
throw new ForbiddenException(__('You are not allowed to access this location.'));
}
$keyString = $this->getRequest()->getData('data');
if (!is_string($keyString) || trim($keyString) === '') {
throw new BadRequestException(__('Subscription key data is required.'));
}
try {
$keyDto = (new SubscriptionKeySaveService())->save($keyString, $this->User->getAccessControl());
} catch (SubscriptionSignatureException $e) {
throw new BadRequestException($e->getMessage());
} catch (SubscriptionException $e) {
throw new PaymentRequiredException($e->getMessage(), $e->getErrors());
}
// POST and PUT both land here for backwards compatibility.
// Preserve the historical success messages of the now-deleted
// SubscriptionsCreateController (POST) and this controller (PUT) so the
// legacy SubscriptionsCreateControllerTest keeps passing unchanged.
$message = $this->getRequest()->is('post')
? __('The subscription was created.')
: __('The subscription was updated.');
$this->success($message, $keyDto->toArray());
}
}
View on GitHub (pinned to 31c1bbc10f)