{"record":{"id":"1562020c2d4fd698","repo":"FlowiseAI/Flowise","slug":"no-subscription-items-found","errorCode":null,"errorMessage":"No subscription items found","messagePattern":"No subscription items found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/IdentityManager.ts","lineNumber":349,"sourceCode":"        if (!subscriptionId) return {}\n        if (!this.stripeManager) {\n            throw new Error('Stripe manager is not initialized')\n        }\n        return await this.stripeManager.getAdditionalSeatsProration(subscriptionId, newQuantity)\n    }\n\n    public async updateAdditionalSeats(subscriptionId: string, quantity: number, prorationDate: number) {\n        if (!subscriptionId) return {}\n\n        if (!this.stripeManager) {\n            throw new Error('Stripe manager is not initialized')\n        }\n        const { success, subscription, invoice } = await this.stripeManager.updateAdditionalSeats(subscriptionId, quantity, prorationDate)\n\n        // Fetch product details to get quotas\n        const items = subscription.items.data\n        if (items.length === 0) {\n            throw new Error('No subscription items found')\n        }\n\n        const productId = items[0].price.product as string\n        const product = await this.stripeManager.getStripe().products.retrieve(productId)\n        const productMetadata = product.metadata\n\n        // Extract quotas from metadata\n        const quotas: Record<string, number> = {}\n        for (const key in productMetadata) {\n            if (key.startsWith('quota:')) {\n                quotas[key] = parseInt(productMetadata[key])\n            }\n        }\n        quotas[LICENSE_QUOTAS.ADDITIONAL_SEATS_LIMIT] = quantity\n\n        // Get features from Stripe\n        const features = await this.getFeaturesByPlan(subscription.id, true)\n","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/server/src/IdentityManager.ts#L331-L367","documentation":"Thrown by IdentityManager.updateAdditionalSeats() after a successful Stripe updateAdditionalSeats call, when subscription.items.data is an empty array. The code assumes at least one line item exists so it can read items[0].price.product to fetch product metadata and quotas; with no items it cannot derive a productId and aborts. This indicates the Stripe subscription returned from the update call has no line items, which is an unexpected Stripe state.","triggerScenarios":"A subscription whose items were all removed/zeroed just before or during the seats update, so the returned subscription object has items.data.length === 0; a subscription in an incomplete/canceled state with no active items; a Stripe test fixture returning an empty items array.","commonSituations":"A subscription that was canceled or drained of items out-of-band; a race between a cancellation webhook and the seats update; misconfigured Stripe test data; a subscription created without any item.","solutions":["Before calling updateAdditionalSeats, verify the subscription has active items (e.g. retrieve it and check items.data.length).","Handle the empty-items case explicitly: return a structured error to the client instead of throwing, if business logic permits.","Re-fetch the subscription and retry if the empty state is transient (e.g. concurrent Stripe webhook).","Inspect the subscription in the Stripe dashboard to confirm its current item state."],"exampleFix":"// before\nconst items = subscription.items.data\nif (items.length === 0) throw new Error('No subscription items found')\nconst productId = items[0].price.product as string\n\n// after\nconst items = subscription.items.data\nif (items.length === 0) {\n    return { success: false, message: 'Subscription has no items; cannot update seats' }\n}\nconst productId = items[0].price.product as string","handlingStrategy":"try-catch","validationCode":"// Pre-fetch the subscription and confirm it has items before the seats update\nconst sub = await stripeManager.getStripe().subscriptions.retrieve(subId)\nif (!sub.items.data.length) {\n    return res.status(409).json({ message: 'Subscription has no items; cannot update seats' })\n}","typeGuard":"const subscriptionHasItems = (sub: { items: { data: unknown[] } }): boolean =>\n    Array.isArray(sub.items.data) && sub.items.data.length > 0","tryCatchPattern":"try {\n    const result = await identityManager.updateAdditionalSeats(subId, qty, prorationDate)\n} catch (e) {\n    if ((e as Error).message === 'No subscription items found') {\n        // data integrity issue — re-fetch to confirm, then surface a 409 or retry once\n        return res.status(409).json({ message: 'Subscription has no items' })\n    }\n    throw e\n}","preventionTips":["Before seats updates, verify the subscription has at least one active item.","Watch for concurrent cancellation webhooks that empty items mid-request.","Validate Stripe test fixtures include items.data with a price.product."],"tags":["stripe","billing","subscription","seats","data-integrity"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}