hcengineering/platform · error

No products configured for plan: ${planKey}

Error message

No products configured for plan: ${planKey}

What it means

updateSubscriptionPlan resolves the new plan to Polar product IDs using getPlanKey(SubscriptionType.Tier, newPlan) and this.subscriptionPlans. If the key is missing or maps to an empty array, there is no Polar product to switch the subscription to, so it throws 'No products configured for plan: <planKey>'. This is a configuration gap in the Polar plan catalog for tier upgrades/downgrades.

Source

Thrown at services/payment/pod-payment/src/providers/polar/provider.ts:295

  async updateSubscriptionPlan (
    ctx: MeasureContext,
    subscriptionId: string,
    newPlan: string,
    workspaceUrl: string,
    accountUuid: string
  ): Promise<SubscriptionData | CheckoutResponse | null> {
    // Get the current subscription to check if it's free
    const currentSub = await this.polar.getSubscription(ctx, subscriptionId)

    // Check if subscription is free by checking if it has a price with amountType === 'free'
    const isFreeSubscription = currentSub.prices?.[0]?.amountType === 'free'

    // Get the Polar product ID for the new plan (subscriptions updates are tier type)
    const planKey = getPlanKey(SubscriptionType.Tier, newPlan)
    const productIds = this.subscriptionPlans[planKey]
    if (productIds === undefined || productIds.length === 0) {
      throw new Error(`No products configured for plan: ${planKey}`)
    }

    // Use first product ID from the list (it should be the default fixed amount subscription plan)
    const newProductId = productIds[0]

    // If subscription is free, create a checkout instead of updating directly
    if (isFreeSubscription) {
      const successUrl = `${this.frontUrl}/workbench/${workspaceUrl}/setting/setting/billing/subscriptions?payment=success&checkout_id={CHECKOUT_ID}`
      const returnUrl = `${this.frontUrl}/workbench/${workspaceUrl}/setting/setting/billing/subscriptions?payment=canceled`

      const response = await this.polar.createCheckout(ctx, {
        productIds: [newProductId],
        successUrl,
        returnUrl,
        subscriptionId: currentSub.id,
        externalCustomerId: accountUuid,
        customerEmail: currentSub.customer?.email ?? undefined,
        customerName: currentSub.customer?.name ?? undefined,

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Populate subscriptionPlans[planKey] with valid Polar product IDs (non-empty array) and redeploy
  2. Verify the incoming newPlan value matches a configured key (check the planKey in the message)
  3. Cross-check product IDs exist in the Polar dashboard and are active
  4. Add a startup validation that every advertised plan has at least one product ID

Example fix

// before
'tier:newplan': []
// after
'tier:newplan': ['prod_newplan_default']
Defensive patterns

Strategy: validation

Validate before calling

const planKey = getPlanKey(SubscriptionType.Tier, newPlan)
const ids = provider.subscriptionPlans?.[planKey]
if (ids === undefined || ids.length === 0) {
  throw new Error(`Cannot switch to plan ${newPlan}: no Polar products configured`)
}

Type guard

function planHasProducts(provider: PolarProvider, planKey: string): boolean {
  return Array.isArray(provider.subscriptionPlans?.[planKey]) && (provider.subscriptionPlans?.[planKey]?.length ?? 0) > 0
}

Try / catch

try {
  await provider.updateSubscriptionPlan(ctx, subscriptionId, newPlan)
} catch (e) {
  if (e.message.startsWith('No products configured for plan')) {
    // reject plan change and notify ops to fix plan catalog
  } else throw e
}

Prevention

When it happens

Trigger: updateSubscriptionPlan called with newPlan whose tier key is absent from subscriptionPlans, or present but with productIds: [] — e.g. a newly advertised plan not yet given product IDs, or config parsed with an empty list.

Common situations: Plan added to billing UI without updating the payment pod's subscriptionPlans config; config file edited leaving 'products: []'; typo causing key mismatch; environment where only some plans are enabled.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/8b94bca44e7512fd. Report an issue: GitHub.