{"record":{"id":"ac84b6332093d09f","repo":"passbolt/passbolt_api","slug":"a-subscription-key-is-already-present","errorCode":null,"errorMessage":"A subscription key is already present.","messagePattern":"A subscription key is already present\\.","errorType":"http","errorClass":"ConflictException","httpStatus":409,"severity":"error","filePath":"plugins/PassboltCe/Edition/src/Controller/EditionSubscriptionsCreateController.php","lineNumber":76,"sourceCode":"        $this->success(__('The subscription was created.'), $keyDto->toArray());\n    }\n\n    /**\n     * Rejects with HTTP 409 if the instance is already on PRO or already has a\n     * persisted subscription row.\n     *\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\ConflictException\n     */\n    private function assertNotAlreadyPro(): void\n    {\n        if ((new EditionGetService())->get()->isPro()) {\n            throw new ConflictException(__('The instance is already on PRO.'));\n        }\n\n        $subscriptions = $this->fetchTable('Passbolt/Subscription.Subscriptions');\n        if ($subscriptions->find()->count() > 0) {\n            throw new ConflictException(__('A subscription key is already present.'));\n        }\n    }\n}\n","sourceCodeStart":58,"sourceCodeEnd":80,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Edition/src/Controller/EditionSubscriptionsCreateController.php#L58-L80","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Delete the existing subscription via the DELETE /edition/subscriptions endpoint, then create the new one","Inspect the subscriptions table and remove stale records if the endpoint is unavailable","Make create requests idempotent in automation (check before POST)"],"exampleFix":"// before\nawait api.post('/edition/subscriptions', {data: key}); // 409 when a key exists\n// after\nawait api.delete('/edition/subscriptions');\nawait api.post('/edition/subscriptions', {data: key});","handlingStrategy":"validation","validationCode":"const subs = await api.get('/edition/subscriptions');\nif (subs.body.length > 0) { /* delete existing key first or skip create */ }","typeGuard":"function hasExistingSubscription(subs: {length: number}): boolean { return subs.length > 0; }","tryCatchPattern":"try {\n  await api.post('/edition/subscriptions', {data: key});\n} catch (e) {\n  if (e.status === 409) { /* a key row exists: DELETE then re-create */ }\n}","preventionTips":["Check for existing subscription rows before create calls","Clean stale subscription records in reused test environments","Guard against double-submission in UIs/scripts"],"tags":["conflict","subscription","duplicate"],"backgroundTag":"file-already-exists","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}