moeru-ai/airi · error · ApiError
STRIPE_NOT_CONFIGURED
STRIPE_NOT_CONFIGURED
Error message
Stripe is not configured
What it means
The webhook operation requires an initialized Stripe client and a configured webhook signing secret. If either is missing, incoming webhook POSTs cannot be verified or processed, so it responds with 503 STRIPE_NOT_CONFIGURED before even checking the signature.
Solutions
- Set STRIPE_WEBHOOK_SECRET (whsec_...) from the Stripe dashboard webhook endpoint settings.
- Ensure the Stripe client initializes (STRIPE_SECRET_KEY present and valid).
- Restart the API after adding the configuration.
- If testing locally, use the Stripe CLI to forward events with a local secret configured.
Example fix
// before (.env) # STRIPE_WEBHOOK_SECRET missing // after STRIPE_WEBHOOK_SECRET=whsec_xxx
Defensive patterns
Strategy: try-catch
Validate before calling
// Server-side startup check
if (!process.env.STRIPE_SECRET_KEY || !process.env.STRIPE_WEBHOOK_SECRET)
throw new Error('Stripe webhook not configured') Try / catch
try {
await forwardWebhook(signature, body)
} catch (e) {
if (e.code === 'STRIPE_NOT_CONFIGURED') {
// do not retry; configure the environment first
}
} Prevention
- Include STRIPE_WEBHOOK_SECRET in deployment config checklists.
- Fail server startup (or mark unhealthy) when Stripe config is missing in production.
- Use Stripe CLI locally with a locally configured secret.
When it happens
Trigger: Stripe POSTing to /webhooks/stripe (or a developer curling it) while stripe is null (no STRIPE_SECRET_KEY at init) or webhookSecret is null (STRIPE_WEBHOOK_SECRET unset).
Common situations: Deploying without setting STRIPE_WEBHOOK_SECRET; running the API locally without any Stripe environment; secret removed during rotation; webhook endpoint registered before backend config completed.
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
- INTERNAL_SERVER_ERROR
- MISSING_SIGNATURE
- STRIPE_NOT_CONFIGURED
- WEBHOOK_ERROR
- Aliyun NLS credentials are incomplete.
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17).
Data as JSON: /api/errors/cf225c9f734a0d85.
Report an issue: GitHub.
Appendix: source
Thrown at server/apps/api/src/routes/stripe/operations/webhook.ts:94
}).onConflictDoNothing()
return legacy.id
}
/**
* Verifies a Stripe webhook, maps a Checkout Session to a claim receipt,
* then calls Payment CORE. Unknown events are ignored.
*/
export function createWebhookOperation(
stripe: Stripe | null,
webhookSecret: string | null,
payment: PaymentService,
db: Database,
metrics: RevenueMetrics | null,
productEventService: ProductEventService | null,
) {
return async (signature: string | null, body: string): Promise<{ received: true }> => {
if (!stripe || !webhookSecret)
throw createServiceUnavailableError('Stripe is not configured', 'STRIPE_NOT_CONFIGURED')
if (!signature)
throw createBadRequestError('No signature', 'MISSING_SIGNATURE')
let event: Stripe.Event
try {
event = stripe.webhooks.constructEvent(body, signature, webhookSecret)
}
catch (err: unknown) {
throw createBadRequestError(`Webhook Error: ${errorMessageFromUnknown(err)}`, 'WEBHOOK_ERROR')
}
logger.withFields({ type: event.type, id: event.id }).log('Webhook event received')
metrics?.stripeEvents.add(1, { event_type: event.type })
switch (event.type) {
case 'checkout.session.completed':
case 'checkout.session.async_payment_succeeded': {View on GitHub (pinned to 438a067dde)