{"record":{"id":"be038103640042b5","repo":"calcom/cal.diy","slug":"stripe-app-not-found","errorCode":null,"errorMessage":"Stripe app not found","messagePattern":"Stripe app not found","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"apps/api/v2/src/modules/stripe/stripe.service.ts","lineNumber":90,"sourceCode":"      },\n      redirect_uri: this.redirectUri,\n      state: JSON.stringify(state),\n    };\n\n    const params = z.record(z.any()).parse(stripeConnectParams);\n    const query = stringify(params);\n    const url = `https://connect.stripe.com/oauth/authorize?${query}`;\n\n    return url;\n  }\n\n  async getStripeAppKeys() {\n    const app = await this.appsRepository.getAppBySlug(\"stripe\");\n\n    const { client_id, client_secret } = stripeKeysResponseSchema.parse(app?.keys);\n\n    if (!client_id) {\n      throw new NotFoundException(\"Stripe app not found\");\n    }\n\n    if (!client_secret) {\n      throw new NotFoundException(\"Stripe app not found\");\n    }\n\n    return { client_id, client_secret };\n  }\n\n  async saveStripeAccount(state: OAuthCallbackState, code: string, userId: number): Promise<{ url: string }> {\n    if (!userId) {\n      throw new UnauthorizedException(\"Invalid Access token.\");\n    }\n\n    const response = await stripeInstance.oauth.token({\n      grant_type: \"authorization_code\",\n      code: code?.toString(),\n    });","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/stripe/stripe.service.ts#L72-L108","documentation":"Thrown by StripeService.getStripeAppKeys after it loads the 'stripe' app by slug and parses app.keys with stripeKeysResponseSchema. The schema requires client_id to be a non-empty string starting with 'ca_', so in practice a malformed client_id throws a ZodError first; this NotFoundException guard is defense-in-depth for the case where parsing somehow yields an empty client_id. Either way the root cause is a missing/misconfigured Stripe app key.","triggerScenarios":"Any Stripe operation that needs the app keys (redirect, save, checkout) when the Stripe app is not installed or its keys JSON lacks a valid client_id (e.g. app.keys is null, or client_id is empty).","commonSituations":"The Stripe app was never installed in this environment. The app's keys were only partially configured (client_secret set but client_id blank). The app record's keys JSON was corrupted or migrated incorrectly. A staging env points at an unseeded database.","solutions":["Install the Stripe app from the app store and set a full key set: client_id (ca_...), client_secret (sk_...), public_key (pk_...), webhook_secret (whsec_).","Verify in the database/apps config that the 'stripe' slug exists and its keys JSON parses with all four prefixed values.","Confirm you are pointed at the environment where the Stripe app is configured."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate Stripe app keys shape before any Stripe operation.\nimport { z } from 'zod';\nconst keysSchema = z.object({\n  client_id: z.string().startsWith('ca_').min(1),\n  client_secret: z.string().startsWith('sk_').min(1),\n  public_key: z.string().startsWith('pk_').min(1),\n  webhook_secret: z.string().startsWith('whsec_').min(1),\n});\nfunction stripeKeysConfigured(app): boolean {\n  return keysSchema.safeParse(app?.keys).success;\n}","typeGuard":"function hasStripeClientId(keys: unknown): boolean {\n  return typeof (keys as any)?.client_id === 'string' && (keys as any).client_id.startsWith('ca_');\n}","tryCatchPattern":"try {\n  await api.stripeRedirect();\n} catch (e) {\n  if (e.status === 404 && /Stripe app not found/.test(e.message)) {\n    surfaceToAdmin('Configure the Stripe app (client_id, client_secret, public_key, webhook_secret).');\n  } else throw e;\n}","preventionTips":["Install and fully configure the Stripe app (all four prefixed keys) in every environment.","Add a startup health check that parses app.keys with the schema and fails fast if invalid.","Keep the app's redirect URI in sync with the Stripe dashboard."],"tags":["stripe","config","app-store","api-v2","keys"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}