FlowiseAI/Flowise · error · InternalFlowiseError

Subscription is canceled

Error message

Subscription is canceled

What it means

Inside getProductIdFromSubscription, after a cache miss the subscription is retrieved from Stripe. If its status is 'canceled', an InternalFlowiseError with HTTP 401 UNAUTHORIZED is thrown. This treats a canceled subscription as an authorization failure: the caller is not entitled to resolve a product for it. The surrounding try/catch swallows all errors and returns '' here, so in this specific method the throw is caught and converted to an empty string.

Source

Thrown at packages/server/src/StripeManager.ts:58

    }

    public async getProductIdFromSubscription(subscriptionId: string) {
        if (!subscriptionId || subscriptionId.trim() === '') {
            return ''
        }

        if (!this.stripe) {
            throw new Error('Stripe is not initialized')
        }

        const subscriptionData = await this.cacheManager.getSubscriptionDataFromCache(subscriptionId)
        if (subscriptionData?.productId) {
            return subscriptionData.productId
        }

        try {
            const subscription = await this.stripe.subscriptions.retrieve(subscriptionId)
            if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled')
            const items = subscription.items.data
            if (items.length === 0) {
                return ''
            }

            const productId = items[0].price.product as string
            await this.cacheManager.updateSubscriptionDataToCache(subscriptionId, {
                productId,
                subsriptionDetails: this.getSubscriptionObject(subscription)
            })

            return productId
        } catch (error) {
            return ''
        }
    }

    public async getFeaturesByPlan(subscriptionId: string, withoutCache: boolean = false) {

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Stop calling billing-dependent APIs for subscriptions known to be canceled (filter by status upstream).
  2. If an empty product response is acceptable, rely on the method's own catch (it returns '' on any error) rather than treating the throw as fatal in the caller.
  3. Reconcile cached subscription status so canceled IDs are short-circuited before the Stripe retrieve.
  4. For genuine re-activation flows, create a new subscription rather than reusing the canceled ID.

Example fix

// before: canceled subscription throws, but caller may not expect it
const subscription = await this.stripe.subscriptions.retrieve(subscriptionId)
if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled')

// after: short-circuit on canceled status without a throw inside the swallowed try
if (subscription.status === 'canceled') return ''
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check subscription status before relying on the product ID
const sub = await stripeManager.getStripe().subscriptions.retrieve(subscriptionId)
if (sub.status === 'canceled') {
    // skip product-dependent logic
    return ''
}

Type guard

function isSubscriptionActive(status: Stripe.Subscription.Status): boolean {
    return status !== 'canceled'
}

Try / catch

// getProductIdFromSubscription swallows errors and returns '' here, so callers
// should treat '' as 'unknown/canceled' rather than catching:
const productId = await stripeManager.getProductIdFromSubscription(subscriptionId)
if (!productId) {
    // handle canceled/unknown subscription without throwing

Prevention

When it happens

Trigger: Passing a subscription ID whose Stripe status is 'canceled' into getProductIdFromSubscription. This happens for ex-customers, after a plan cancellation completes, or when a webhook/job retries against a stale subscription ID.

Common situations: User cancelled their plan and a background job still references the old subscription. Test fixtures using a canceled test subscription. Race where cancellation webhook lands before an in-flight request completes.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/26db7edf59e19639. Report an issue: GitHub.