moeru-ai/airi · error · ApiError

INVALID_PACKAGE

INVALID_PACKAGE

Error message

Invalid price

What it means

The submitted stripePriceId is valid syntactically but priceCatalog.findActivePrice found no active price matching it for the configured flux product. The API rejects with 400 INVALID_PACKAGE because checkout cannot bill against an unknown, inactive, or foreign price.

Solutions

  1. Use a price ID that belongs to the product configured as STRIPE_FLUX_PRODUCT_ID and is currently active.
  2. Fetch the current active price from the price catalog/API instead of hardcoding it in the client.
  3. Verify you are hitting the right environment (test vs live mode price IDs differ).
  4. Re-create/activate the price in Stripe if it was archived unintentionally.

Example fix

// before
body: { stripePriceId: 'price_old_archived', currency: 'usd' }
// after
body: { stripePriceId: await fetchActivePriceId(), currency: 'usd' }
Defensive patterns

Strategy: validation

Validate before calling

// Only offer prices known to be active and belonging to the flux product
const activePriceIds = new Set((await fetchCatalogPrices()).map(p => p.id))
if (!activePriceIds.has(stripePriceId)) throw new Error('price not in active catalog')

Try / catch

try {
  await checkout({ stripePriceId, currency })
} catch (e) {
  if (e.code === 'INVALID_PACKAGE') {
    // refresh price catalog and ask user to reselect
  }
}

Prevention

When it happens

Trigger: POSTing checkout with a stripePriceId that belongs to a different Stripe product than STRIPE_FLUX_PRODUCT_ID, an archived/inactive price, or a typo/nonexistent price ID.

Common situations: Hardcoded price IDs left over after re-creating prices in Stripe dashboard; staging client pointing at production price IDs (or vice versa); price archived during a pricing change while clients still cache it.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17). Data as JSON: /api/errors/55464ddeb75cf66e. Report an issue: GitHub.

Appendix: source

Thrown at server/apps/api/src/routes/stripe/operations/checkout.ts:41

  productEventService: ProductEventService | null,
) {
  return async (
    user: { id: string, email: string },
    body: unknown,
    request: Request,
  ): Promise<{ url: string }> => {
    const fluxProductId = await configKV.getOptional('STRIPE_FLUX_PRODUCT_ID')
    if (!stripe || !priceCatalog || !fluxProductId)
      throw createServiceUnavailableError('Stripe is not configured', 'STRIPE_NOT_CONFIGURED')

    const parsed = safeParse(CheckoutBodySchema, body)
    if (!parsed.success)
      throw createBadRequestError('Invalid checkout request', 'INVALID_REQUEST', parsed.issues)

    const { stripePriceId, currency } = parsed.output
    const price = await priceCatalog.findActivePrice(fluxProductId, stripePriceId)
    if (!price)
      throw createBadRequestError('Invalid price', 'INVALID_PACKAGE', { stripePriceId })

    const fluxAmount = Number(price.metadata.fluxAmount)
    if (!Number.isFinite(fluxAmount) || fluxAmount <= 0)
      throw createBadRequestError('Price is missing fluxAmount metadata', 'INVALID_PACKAGE', { stripePriceId })

    const redirectBase = resolveCheckoutRedirectBase(request, env.ADDITIONAL_TRUSTED_ORIGINS, env.WEB_APP_URL)
    const openpanelIdentity = readOpenpanelIdentityHeaders(request)

    const order = await payment.openPending({
      userId: user.id,
      processor: 'stripe',
      packKey: stripePriceId,
      fluxAmount,
      currency,
    })

    const sessionParams: Stripe.Checkout.SessionCreateParams = {
      line_items: [{ price: stripePriceId, quantity: 1 }],

View on GitHub (pinned to 438a067dde)