calcom/cal.diy · error · BadRequestException
Invalid stripe credentials.
Error message
Invalid stripe credentials.
What it means
Thrown by StripeService.validateStripeCredentials when the user's stripe_payment credential exists but its `invalid` flag is true. The flag is set when a prior Stripe API operation detected the credentials no longer work (e.g. revoked access), so validation short-circuits to 400 BadRequest without calling Stripe again.
Source
Thrown at apps/api/v2/src/modules/stripe/stripe.service.ts:153
async checkIfIndividualStripeAccountConnected(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
const stripeCredentials = await this.credentialsRepository.findCredentialByTypeAndUserId(
"stripe_payment",
userId
);
return await this.validateStripeCredentials(stripeCredentials);
}
async validateStripeCredentials(
credentials?: Credential | null
): Promise<{ status: typeof SUCCESS_STATUS }> {
if (!credentials) {
throw new NotFoundException("Credentials for stripe not found.");
}
if (credentials.invalid) {
throw new BadRequestException("Invalid stripe credentials.");
}
const stripeKey = JSON.stringify(credentials.key);
const stripeKeyObject = JSON.parse(stripeKey);
const stripeAccount = await stripeInstance.accounts.retrieve(stripeKeyObject?.stripe_user_id);
// both of these should be true for an account to be fully active
if (!stripeAccount.payouts_enabled || !stripeAccount.charges_enabled) {
throw new BadRequestException("Stripe account is not an active account");
}
return {
status: SUCCESS_STATUS,
};
}
async generateTeamCheckoutSession(pendingPaymentTeamId: number, ownerId: number) {View on GitHub (pinned to 176037d0af)
Solutions
- Reconnect Stripe by running the OAuth connect flow again to replace the credentials with fresh ones (clearing the invalid flag).
- Confirm in the Stripe account under Authorized Applications that the Cal app is still approved.
- If the invalid flag was set in error, clear it after verifying the keys work via a Stripe API call.
Defensive patterns
Strategy: try-catch
Validate before calling
async function ensureValidStripeCredentials(api) {
try {
const { status } = await api.validateStripe();
return status === 'success';
} catch (e) {
if (e.status === 400 && /Invalid stripe credentials/.test(e.message)) return false;
throw e;
}
} Type guard
function isCredentialMarkedInvalid(cred: { invalid?: boolean } | null): boolean {
return !!cred?.invalid;
} Try / catch
try {
await api.validateStripe();
} catch (e) {
if (e.status === 400 && /Invalid stripe credentials/.test(e.message)) {
// prompt user to reconnect Stripe
await api.reconnectStripe();
} else throw e;
} Prevention
- Surface an 'invalid credentials - reconnect' prompt rather than a generic error when this fires.
- Periodically validate credentials and proactively prompt reconnection if Stripe revokes access.
- After any Stripe 401 during normal operation, mark credentials invalid and revalidate.
When it happens
Trigger: Calling validate after the credential row was marked invalid by a previous failed Stripe API call (the invalid flag was flipped to true), or after an admin manually marked it invalid.
Common situations: The user revoked access in their Stripe account. The Stripe refresh/access token expired or was invalidated. A prior API call hit a 401 from Stripe and the system marked the credential invalid. A disconnect was partial.
Related errors
- Credentials for stripe not found.
- Missing `state` query param
- error=${error}&error_description=${error_description}
- Invalid Access token.
- Stripe app not found
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/aef0ea57db5fe8b4.
Report an issue: GitHub.