passbolt/passbolt_api · error · PaymentRequiredException
$e->getMessage() (from SubscriptionException)
Error message
$e->getMessage() (from SubscriptionException)
What it means
Other SubscriptionException failures from EditionUpgradeService::upgrade() (non-signature issues) are rethrown as PaymentRequiredException with the original message and errors. This typically means the key is structurally readable but rejected for subscription reasons such as expiry or licensing terms.
Solutions
- Check the key's expiry date and obtain a renewed subscription key from passbolt
- Read the error details returned in the PaymentRequired error body for the specific rejection reason
- Synchronize the server clock (NTP) if expiry-related
- Contact passbolt sales/support if the key should be valid
Example fix
// before // old expired key.txt used for import // after // download renewed subscription key and import it
Defensive patterns
Strategy: try-catch
Validate before calling
// check key expiry metadata before import if available const expired = keyMeta && new Date(keyMeta.expires) < new Date();
Try / catch
try {
await api.post('/edition/subscriptions', {data: key});
} catch (e) {
if (e.status === 402) { /* PaymentRequired: renew key; inspect e.errors for reason */ }
} Prevention
- Track subscription expiry and renew proactively
- Keep server clocks synchronized via NTP
- Store error body details when a 402 is returned
When it happens
Trigger: upgrade() throws SubscriptionException other than a signature failure — e.g. expired subscription key, key data that cannot be parsed into a valid subscription record, or license terms violation.
Common situations: Importing an expired PRO key; renewing with a stale key; a key generated for a different passbolt edition; server clock skew making a valid key appear expired.
Related errors
- A subscription key is already present.
- $e->getMessage() (from SubscriptionSignatureException)
- Only administrators can update the subscription details.
- Only administrators can view the subscription details.
- Subscription key could not be found.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/4e1aefe7959cf045.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Edition/src/Controller/EditionSubscriptionsCreateController.php:55
* @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)