hcengineering/platform · error

Failed to cancel subscription ${providerSubscriptionId}

Error message

Failed to cancel subscription ${providerSubscriptionId}

What it means

cancelSubscription calls the Polar API to cancel, then converts the returned subscription to internal SubscriptionData via transformPolarSubscriptionToData. If the transform returns null (the returned subscription is in a shape/state the transformer does not recognize), the provider cannot honor the cancellation result and throws 'Failed to cancel subscription <id>'. The API call itself may have succeeded; the failure is in interpreting the response.

Source

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

      ctx.info('Polar subscription reconciliation completed', {
        polarActiveCount: polarActiveSubscriptions.length,
        ourActiveCount: ourActiveSubscriptions.length,
        upsertedCount: upsertCount,
        staleUpdatedCount: staleCount
      })
    } catch (err) {
      ctx.error('Polar subscription reconciliation failed', { err })
      throw err
    }
  }

  async cancelSubscription (ctx: MeasureContext, providerSubscriptionId: string): Promise<SubscriptionData> {
    const polarSubscription = await this.polar.cancelSubscription(ctx, providerSubscriptionId)
    const subscriptionData = transformPolarSubscriptionToData(polarSubscription)

    if (subscriptionData == null) {
      throw new Error(`Failed to cancel subscription ${providerSubscriptionId}`)
    }

    return subscriptionData
  }

  async uncancelSubscription (ctx: MeasureContext, providerSubscriptionId: string): Promise<SubscriptionData> {
    const polarSubscription = await this.polar.uncancelSubscription(ctx, providerSubscriptionId)
    const subscriptionData = transformPolarSubscriptionToData(polarSubscription)
    if (subscriptionData == null) {
      throw new Error(`Failed to uncancel subscription ${providerSubscriptionId}`)
    }

    return subscriptionData
  }

  async updateSubscriptionPlan (
    ctx: MeasureContext,
    subscriptionId: string,

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Inspect the raw Polar response for that subscriptionId and update transformPolarSubscriptionToData to handle its shape/status
  2. Check whether the subscription is already canceled server-side (idempotent retry path) before re-failing
  3. Pin/align the Polar SDK version with the transformer's expectations
  4. Add logging in the transformer to record why it returned null

Example fix

// before
const subscriptionData = transformPolarSubscriptionToData(polarSubscription)
if (subscriptionData == null) {
  throw new Error(`Failed to cancel subscription ${providerSubscriptionId}`)
}
// after (caller idempotency guard)
const sub = await getSubscription(ctx, providerSubscriptionId)
if (sub?.status === 'canceled') return sub
const subscriptionData = await provider.cancelSubscription(ctx, providerSubscriptionId)
Defensive patterns

Strategy: try-catch

Validate before calling

const current = await provider.getSubscription(ctx, providerSubscriptionId)
if (current == null) throw new Error(`Subscription ${providerSubscriptionId} unknown to provider`)

Type guard

function isPolarSubscription(x: unknown): x is PolarSubscription {
  return typeof x === 'object' && x !== null && 'id' in x && 'status' in x
}

Try / catch

try {
  await provider.cancelSubscription(ctx, providerSubscriptionId)
} catch (e) {
  if (e.message.startsWith('Failed to cancel subscription')) {
    // verify actual state in Polar before retry; may already be canceled
  } else throw e
}

Prevention

When it happens

Trigger: polar.cancelSubscription returns a subscription object whose fields (prices, product, status) make transformPolarSubscriptionToData return null — e.g. unexpected status value, missing prices array, or a Polar API schema change — for subscription id <id>.

Common situations: Polar API/SDK version bump changing response shape; subscription already fully canceled/expired so the response omits fields; sandbox vs production product data differences; transformer not updated for new Polar subscription states.

Related errors


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