passbolt/passbolt_api · error · BadRequestException

$e->getMessage() (from SubscriptionSignatureException)

Error message

$e->getMessage() (from SubscriptionSignatureException)

What it means

When EditionUpgradeService::upgrade() throws SubscriptionSignatureException (the subscription key's signature could not be verified), the controller rethrows it as BadRequestException carrying the original message. It means the supplied key fails cryptographic validation against passbolt's signing keys.

Solutions

  1. Re-copy the subscription key exactly as provided, without added whitespace or line breaks
  2. Verify the key is issued for this instance (correct domain/subscription id)
  3. Contact passbolt support to obtain a valid signed key
  4. Check the key file was not modified after download

Example fix

// before
$data = file_get_contents('key.asc'); // includes email quote wrapping -> invalid signature
// after
$data = trim(file_get_contents('key.asc')); // exact, unmodified key string
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check: key is an unmodified ASCII armored string, no extra quotes/line wrapping
if (preg_match('/[^[:print:][:space:]]/', $key)) { /* reject corrupted key */ }

Type guard

function looksLikeSignedKey(string $s): bool { return str_contains($s, '-----BEGIN') && trim($s) === $s; }

Try / catch

try {
  await api.post('/edition/subscriptions', {data: key});
} catch (e) {
  if (e.status === 400) { /* signature invalid: re-copy key exactly, verify with provider */ }
}

Prevention

When it happens

Trigger: Upgrading with a subscription key whose signature is invalid, tampered, corrupted in transit, or signed for a different edition/domain.

Common situations: Key file truncated or line-wrapped by copy/paste or email; key issued for a different passbolt instance or domain; using a CE key where PRO is required; expired or revoked 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


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/8420d005b7c7ea49. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/Edition/src/Controller/EditionSubscriptionsCreateController.php:53

    /**
     * @return void
     */
    public function create(): void
    {
        $this->User->assertIsAdmin();

        $keyString = $this->getRequest()->getData('data');
        if (!is_string($keyString) || trim($keyString) === '') {
            throw new BadRequestException(__('Subscription key data is required.'));
        }

        $this->assertNotAlreadyPro();

        try {
            $keyDto = (new EditionUpgradeService())->upgrade($keyString, $this->User->getAccessControl());
        } catch (SubscriptionSignatureException $e) {
            throw new BadRequestException($e->getMessage());
        } catch (SubscriptionException $e) {
            throw new PaymentRequiredException($e->getMessage(), $e->getErrors());
        }

        $this->success(__('The subscription was created.'), $keyDto->toArray());
    }

    /**
     * Rejects with HTTP 409 if the instance is already on PRO or already has a
     * persisted subscription row.
     *
     * @return void
     * @throws \Cake\Http\Exception\ConflictException
     */
    private function assertNotAlreadyPro(): void
    {
        if ((new EditionGetService())->get()->isPro()) {
            throw new ConflictException(__('The instance is already on PRO.'));

View on GitHub (pinned to 31c1bbc10f)