{"record":{"id":"d985fad43d22c4f8","repo":"moeru-ai/airi","slug":"stripe-not-configured","errorCode":"STRIPE_NOT_CONFIGURED","errorMessage":"Stripe is not configured","messagePattern":"Stripe is not configured","errorType":"http","errorClass":"ApiError","httpStatus":503,"severity":"error","filePath":"server/apps/api/src/routes/stripe/operations/checkout.ts","lineNumber":32,"sourceCode":"import { CheckoutBodySchema } from '../schema'\n\nexport function createCheckoutOperation(\n  payment: PaymentService,\n  stripe: Stripe | null,\n  priceCatalog: StripePriceCatalog | null,\n  configKV: ConfigKVService,\n  env: Env,\n  metrics: RevenueMetrics | null,\n  productEventService: ProductEventService | null,\n) {\n  return async (\n    user: { id: string, email: string },\n    body: unknown,\n    request: Request,\n  ): Promise<{ url: string }> => {\n    const fluxProductId = await configKV.getOptional('STRIPE_FLUX_PRODUCT_ID')\n    if (!stripe || !priceCatalog || !fluxProductId)\n      throw createServiceUnavailableError('Stripe is not configured', 'STRIPE_NOT_CONFIGURED')\n\n    const parsed = safeParse(CheckoutBodySchema, body)\n    if (!parsed.success)\n      throw createBadRequestError('Invalid checkout request', 'INVALID_REQUEST', parsed.issues)\n\n    const { stripePriceId, currency } = parsed.output\n    const price = await priceCatalog.findActivePrice(fluxProductId, stripePriceId)\n    if (!price)\n      throw createBadRequestError('Invalid price', 'INVALID_PACKAGE', { stripePriceId })\n\n    const fluxAmount = Number(price.metadata.fluxAmount)\n    if (!Number.isFinite(fluxAmount) || fluxAmount <= 0)\n      throw createBadRequestError('Price is missing fluxAmount metadata', 'INVALID_PACKAGE', { stripePriceId })\n\n    const redirectBase = resolveCheckoutRedirectBase(request, env.ADDITIONAL_TRUSTED_ORIGINS, env.WEB_APP_URL)\n    const openpanelIdentity = readOpenpanelIdentityHeaders(request)\n\n    const order = await payment.openPending({","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/moeru-ai/airi/blob/438a067dde47aa0bdb46c2323d1fe293dc805218/server/apps/api/src/routes/stripe/operations/checkout.ts#L14-L50","documentation":"createCheckoutOperation requires three configured pieces: a Stripe client, a price catalog, and the STRIPE_FLUX_PRODUCT_ID config value. If any is missing (Stripe integration not initialized or product ID not set), checkout cannot proceed and the API returns 503 with STRIPE_NOT_CONFIGURED.","triggerScenarios":"POSTing to the checkout route while: stripe client is null (STRIPE_SECRET_KEY missing/invalid at init), priceCatalog is null, or configKV has no 'STRIPE_FLUX_PRODUCT_ID' entry.","commonSituations":"Deploying without setting STRIPE_SECRET_KEY or STRIPE_FLUX_PRODUCT_ID in the environment/config KV; running the API locally against a docker-compose stack where Stripe config was never seeded; key rotation left the client uninitialized.","solutions":["Set STRIPE_FLUX_PRODUCT_ID via configKV (or your config mechanism) to a valid Stripe product ID.","Ensure the Stripe client is initialized (verify STRIPE_SECRET_KEY is present and valid at server startup).","Verify the price catalog loads successfully (check its initialization logs/dependencies).","Restart the API after adding the configuration so dependencies re-initialize."],"exampleFix":"// before (config missing)\n// configKV has no STRIPE_FLUX_PRODUCT_ID\n// after\nawait configKV.set('STRIPE_FLUX_PRODUCT_ID', 'prod_xxx')","handlingStrategy":"try-catch","validationCode":"const fluxProductId = await configKV.getOptional('STRIPE_FLUX_PRODUCT_ID')\nif (!stripe || !priceCatalog || !fluxProductId) {\n  // disable checkout UI / show 'billing unavailable'\n}","typeGuard":null,"tryCatchPattern":"try {\n  const { url } = await api.post('/checkout', body)\n} catch (e) {\n  if (e.code === 'STRIPE_NOT_CONFIGURED') {\n    // show 'payments are not available yet' message, do not retry\n  }\n}","preventionTips":["Add a startup readiness check that fails fast when STRIPE_SECRET_KEY or STRIPE_FLUX_PRODUCT_ID is absent.","Health-check endpoint should report Stripe config status.","Keep checkout UI disabled until /health confirms billing readiness."],"tags":["stripe","configuration","service-unavailable"],"backgroundTag":"missing-env-var","analyzedSha":"438a067dde47aa0bdb46c2323d1fe293dc805218","analyzedAt":"2026-09-17T01:14:42.644Z","contentChangedAt":"2026-09-17T01:14:42.644Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}