moeru-ai/airi · error · ApiError
STRIPE_NOT_CONFIGURED
STRIPE_NOT_CONFIGURED
Error message
Stripe is not configured
What it means
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.
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.
Example fix
// before (config missing)
// configKV has no STRIPE_FLUX_PRODUCT_ID
// after
await configKV.set('STRIPE_FLUX_PRODUCT_ID', 'prod_xxx') Defensive patterns
Strategy: try-catch
Validate before calling
const fluxProductId = await configKV.getOptional('STRIPE_FLUX_PRODUCT_ID')
if (!stripe || !priceCatalog || !fluxProductId) {
// disable checkout UI / show 'billing unavailable'
} Try / catch
try {
const { url } = await api.post('/checkout', body)
} catch (e) {
if (e.code === 'STRIPE_NOT_CONFIGURED') {
// show 'payments are not available yet' message, do not retry
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- STRIPE_CHECKOUT_URL_MISSING
- STRIPE_NOT_CONFIGURED
- Aliyun NLS credentials are incomplete.
- Failed to initialize speech provider
- Failed to initialize speech provider
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17).
Data as JSON: /api/errors/d985fad43d22c4f8.
Report an issue: GitHub.
Appendix: source
Thrown at server/apps/api/src/routes/stripe/operations/checkout.ts:32
import { CheckoutBodySchema } from '../schema'
export function createCheckoutOperation(
payment: PaymentService,
stripe: Stripe | null,
priceCatalog: StripePriceCatalog | null,
configKV: ConfigKVService,
env: Env,
metrics: RevenueMetrics | null,
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({View on GitHub (pinned to 438a067dde)