{"record":{"id":"79f9b0ee4bf15958","repo":"TryGhost/Ghost","slug":"cannot-disconnect-stripe-whilst-you-have-active-su","errorCode":null,"errorMessage":"Cannot disconnect Stripe whilst you have active subscriptions.","messagePattern":"Cannot disconnect Stripe whilst you have active subscriptions\\.","errorType":"http","errorClass":"BadRequestError","httpStatus":400,"severity":"error","filePath":"ghost/core/core/server/api/endpoints/settings.js","lineNumber":93,"sourceCode":"            // We need to return all settings here, because we have calculated settings that might change\n            const browse = await settingsBREADService.browse(frame.options.context);\n\n            return browse;\n        }\n    },\n\n    disconnectStripeConnectIntegration: {\n        statusCode: 204,\n        headers: {\n            cacheInvalidate: false\n        },\n        permissions: {\n            method: 'edit'\n        },\n        async query(frame) {\n            const paidMembers = await membersService.api.memberBREADService.browse({limit: 0, filter: 'status:paid'});\n            if (_.get(paidMembers, 'meta.pagination.total') !== 0) {\n                throw new BadRequestError({\n                    message: 'Cannot disconnect Stripe whilst you have active subscriptions.'\n                });\n            }\n\n            await stripeService.disconnect();\n\n            return models.Settings.edit([{\n                key: 'stripe_connect_publishable_key',\n                value: null\n            }, {\n                key: 'stripe_connect_secret_key',\n                value: null\n            }, {\n                key: 'stripe_connect_livemode',\n                value: null\n            }, {\n                key: 'stripe_connect_display_name',\n                value: null","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/ghost/core/core/server/api/endpoints/settings.js#L75-L111","documentation":"Thrown by the `disconnectStripeConnectIntegration` Admin API endpoint when paid members still exist. Before clearing the Stripe keys, Ghost counts members with `status:paid`; if the total is non-zero it refuses to disconnect to avoid orphaning active subscriptions. It is a deliberate data-integrity guard returning a 400 BadRequestError.","triggerScenarios":"An admin calls `DELETE /ghost/api/admin/stripe/connect/` (disconnect) while at least one member has `status:paid`. The endpoint browses paid members and aborts before `stripeService.disconnect()` and the key-clearing edit.","commonSituations":"Trying to reconfigure Stripe without first cancelling or downgrading paid members; leftover paid members from prior testing; a subscription webhook created a paid member after the admin believed all were removed; importing members with paid status.","solutions":["Cancel or downgrade all paid members first (so `status:paid` count is zero), then retry disconnect.","Bulk-cancel subscriptions via the Admin API before disconnecting Stripe Connect.","Verify no pending Stripe webhooks will recreate paid members between cleanup and disconnect.","If this is a test environment, reset member subscriptions through the appropriate teardown flow."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before disconnecting, confirm zero paid members\nconst paid = await api.members.browse({limit: 0, filter: 'status:paid'});\nif (paid.meta.pagination.total !== 0) {\n    throw new Error(`Cannot disconnect: ${paid.meta.pagination.total} paid member(s) still active`);\n}","typeGuard":null,"tryCatchPattern":"try {\n    await api.stripe.disconnect();\n} catch (err) {\n    if (/active subscriptions/i.test((err as Error).response.body.errors[0].message)) {\n        // cancel subscriptions first, then retry\n    }\n    throw err;\n}","preventionTips":["Cancel or downgrade all paid members before disconnecting Stripe.","Verify no pending webhooks will recreate paid members between cleanup and disconnect.","In test environments, use the proper teardown flow rather than manual disconnect."],"tags":["api","stripe","validation","members","admin-api"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}