Skip to content

Commit 5de08a9

Browse files
committed
fix(billing): prevent auto-topup from being disabled on transient errors
- Only disable auto-topup for permanent validation errors (missing customer, no payment method, expired card) - Non-validation errors (Stripe API issues, network errors) now return blocked reason with actual error message but do not disable the setting - Auto-topup will retry on next trigger for transient failures
1 parent f7d8563 commit 5de08a9

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

packages/billing/src/auto-topup.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,21 @@ export async function validateAutoTopupStatus(params: {
106106
} catch (error) {
107107
logger.error({ error }, 'Failed to validate auto top-up status')
108108

109-
const blockedReason =
110-
error instanceof AutoTopupValidationError
111-
? error.message
112-
: 'Unable to verify payment method status.'
113-
114-
await disableAutoTopup({ ...params, reason: blockedReason })
109+
// Only disable auto-topup for permanent validation errors (missing customer, no payment method, expired card)
110+
// Don't disable for transient errors (Stripe API issues, network errors) to avoid false disables
111+
if (error instanceof AutoTopupValidationError) {
112+
await disableAutoTopup({ ...params, reason: error.message })
113+
return {
114+
blockedReason: error.message,
115+
validPaymentMethod: null,
116+
}
117+
}
115118

119+
// For non-validation errors (e.g. Stripe API issues), return blocked but don't disable the setting
120+
// The user's auto-topup will be retried on the next trigger
121+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
116122
return {
117-
blockedReason,
123+
blockedReason: `Unable to verify payment method status: ${errorMessage}`,
118124
validPaymentMethod: null,
119125
}
120126
}
@@ -295,13 +301,20 @@ export async function checkAndTriggerAutoTopup(params: {
295301
})
296302
return amountToTopUp // Return the amount that was successfully added
297303
} catch (error) {
298-
const message =
299-
error instanceof AutoTopupPaymentError
300-
? error.message
301-
: 'Payment failed. Please check your payment method and re-enable auto top-up.'
304+
// Only disable auto-topup for permanent payment errors (card declined, requires action)
305+
// Don't disable for transient errors (Stripe API issues, network errors)
306+
if (error instanceof AutoTopupPaymentError) {
307+
const message = error.message
308+
await disableAutoTopup({ ...params, reason: message })
309+
throw new Error(message)
310+
}
302311

303-
await disableAutoTopup({ ...params, reason: message })
304-
throw new Error(message)
312+
// For transient errors, log but don't disable - will retry on next trigger
313+
logger.warn(
314+
{ userId, error },
315+
'Auto top-up payment failed due to transient error, will retry on next trigger',
316+
)
317+
throw error
305318
}
306319
} catch (error) {
307320
logger.error(

0 commit comments

Comments
 (0)