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
- Populate subscriptionPlans[planKey] with valid Polar product IDs (non-empty array) and redeploy
- Verify the incoming newPlan value matches a configured key (check the planKey in the message)
- Cross-check product IDs exist in the Polar dashboard and are active
- 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
- Startup-validate that every plan key in config has a non-empty product array
- Sync plan catalog config whenever billing UI adds a plan
- Guard against empty arrays in config parsing, not just undefined
- Match newPlan values against a whitelist of configured tiers
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
- Missing productIds for plan: ${planKey}
- Payment service URL not specified
- Authentication token not specified
- Failed to cancel subscription ${providerSubscriptionId}
- Failed to uncancel subscription ${providerSubscriptionId}
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/8b94bca44e7512fd.
Report an issue: GitHub.