{"record":{"id":"c8ef63a3d7ceca07","repo":"FlowiseAI/Flowise","slug":"customer-id-is-required","errorCode":null,"errorMessage":"Customer ID is required","messagePattern":"Customer ID is required","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/StripeManager.ts","lineNumber":129,"sourceCode":"            }\n        }\n\n        await this.cacheManager.updateSubscriptionDataToCache(subscriptionId, {\n            features,\n            subsriptionDetails: this.getSubscriptionObject(subscription)\n        })\n\n        return features\n    }\n\n    public async createStripeCustomerPortalSession(req: Request) {\n        if (!this.stripe) {\n            throw new Error('Stripe is not initialized')\n        }\n\n        const customerId = req.user?.activeOrganizationCustomerId\n        if (!customerId) {\n            throw new Error('Customer ID is required')\n        }\n\n        const subscriptionId = req.user?.activeOrganizationSubscriptionId\n        if (!subscriptionId) {\n            throw new Error('Subscription ID is required')\n        }\n\n        try {\n            const prodPriceIds = await this.getPriceIds()\n            const configuration = await this.createPortalConfiguration(prodPriceIds)\n\n            const portalSession = await this.stripe.billingPortal.sessions.create({\n                customer: customerId,\n                configuration: configuration.id,\n                return_url: `${process.env.APP_URL}/account`\n                /* We can't have flow_data because it does not support multiple subscription items\n                flow_data: {\n                    type: 'subscription_update',","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/server/src/StripeManager.ts#L111-L147","documentation":"createStripeCustomerPortalSession builds a Stripe billing portal session and requires the caller's authenticated user object to carry activeOrganizationCustomerId. The value is read from req.user.activeOrganizationCustomerId; if it's falsy (undefined, null, empty), a generic Error is thrown before any Stripe call. This is a session/auth-state precondition: the user must belong to an organization with a Stripe customer record.","triggerScenarios":"An authenticated request to the portal-session endpoint by a user whose active organization has no linked Stripe customer ID. Typical for newly created organizations, personal-workspace-only users, or users who switched active org to one without billing setup.","commonSituations":"User invited to an org that never completed checkout. activeOrganizationCustomerId not populated by the auth/middleware layer. Session stale after org switch. Self-hosted deployment without org billing wired up.","solutions":["Ensure the user's active organization has a Stripe customer created (run signup/checkout first) so activeOrganizationCustomerId is populated.","Verify the auth middleware populates req.user.activeOrganizationCustomerId from the org record on each request.","On the client, only show the billing-portal action when the org has billing set up; otherwise prompt the user to subscribe.","If the user switched organizations, reload their session/profile so the active org's customer ID is current."],"exampleFix":"// before\nconst customerId = req.user?.activeOrganizationCustomerId\nif (!customerId) {\n    throw new Error('Customer ID is required')\n}\n\n// after: structured error with a hint to the caller\nif (!customerId) {\n    throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'Active organization has no Stripe customer. Complete checkout first.')\n}","handlingStrategy":"validation","validationCode":"// Validate auth state before calling the portal endpoint\nfunction requireOrgCustomer(user: unknown): asserts user is { activeOrganizationCustomerId: string } {\n    const u = user as any\n    if (!u?.activeOrganizationCustomerId) {\n        throw new Error('Active organization has no Stripe customer. Complete checkout first.')\n    }\n}\nrequireOrgCustomer(req.user)","typeGuard":"function hasOrgCustomerId(user: unknown): user is { activeOrganizationCustomerId: string } {\n    return typeof (user as any)?.activeOrganizationCustomerId === 'string' && (user as any).activeOrganizationCustomerId.length > 0\n}","tryCatchPattern":"try {\n    const session = await stripeManager.createStripeCustomerPortalSession(req)\n} catch (err) {\n    if (err instanceof Error && err.message === 'Customer ID is required') {\n        return res.status(StatusCodes.BAD_REQUEST).json({ error: 'No billing account for this organization' })\n    }\n    throw err\n}","preventionTips":["Ensure the auth middleware populates activeOrganizationCustomerId from the org record on each request.","Only expose the billing-portal action after the org completes checkout.","Reload the user's profile after switching organizations.","Gate the portal route with a middleware that verifies org billing state."],"tags":["stripe","billing","billing-portal","authentication","validation"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}