passbolt/passbolt_api · error · ConflictException

A subscription key is already present.

Error message

A subscription key is already present.

What it means

assertNotAlsoPro's second check: if the Subscriptions table already contains a row, creating another subscription key is rejected with ConflictException. The create endpoint only works on a clean instance with no stored subscription record.

Solutions

  1. Delete the existing subscription via the DELETE /edition/subscriptions endpoint, then create the new one
  2. Inspect the subscriptions table and remove stale records if the endpoint is unavailable
  3. Make create requests idempotent in automation (check before POST)

Example fix

// before
await api.post('/edition/subscriptions', {data: key}); // 409 when a key exists
// after
await api.delete('/edition/subscriptions');
await api.post('/edition/subscriptions', {data: key});
Defensive patterns

Strategy: validation

Validate before calling

const subs = await api.get('/edition/subscriptions');
if (subs.body.length > 0) { /* delete existing key first or skip create */ }

Type guard

function hasExistingSubscription(subs: {length: number}): boolean { return subs.length > 0; }

Try / catch

try {
  await api.post('/edition/subscriptions', {data: key});
} catch (e) {
  if (e.status === 409) { /* a key row exists: DELETE then re-create */ }
}

Prevention

When it happens

Trigger: POSTing a subscription key when any row exists in the Passbolt/Subscription.Subscriptions table, even if the edition is not yet PRO (e.g. a stale or legacy key record).

Common situations: Re-importing after a partial upgrade; leftover subscription row from a previous trial; test environment reused without clearing the subscriptions table; double-submitted create request.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

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

        $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.'));
        }

        $subscriptions = $this->fetchTable('Passbolt/Subscription.Subscriptions');
        if ($subscriptions->find()->count() > 0) {
            throw new ConflictException(__('A subscription key is already present.'));
        }
    }
}

View on GitHub (pinned to 31c1bbc10f)