{"record":{"id":"88fe6dafea1666f2","repo":"koala73/worldmonitor","slug":"dodo-api-key-missing","errorCode":"DODO_API_KEY_MISSING","errorMessage":"DODO_API_KEY_MISSING","messagePattern":"DODO_API_KEY_MISSING","errorType":"exception","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/payments/billing.ts","lineNumber":54,"sourceCode":"/**\n * Returns the direct DodoPayments REST SDK client owned by this billing module.\n *\n * This client handles billing, customer portal, and subscription operations.\n * lib/dodo.ts independently owns direct REST checkout-session creation;\n * webhook verification lives in payments/webhookHandlers.ts.\n *\n * Canonical env var: DODO_API_KEY.\n */\nfunction getDodoClient(\n  options: { timeout?: number; maxRetries?: number } = {},\n): DodoPayments {\n  const apiKey = process.env.DODO_API_KEY;\n  if (!apiKey) {\n    // Structured throw (object-typed `data`) so the client receives\n    // `err.data.kind` instead of an opaque `[Request ID: X] Server Error`\n    // (Convex's HTTP runtime drops `errorData` for string-data throws).\n    // Surfaces a config drift bug at error level so on-call sees the real cause.\n    throw new ConvexError({ kind: \"DODO_API_KEY_MISSING\" });\n  }\n  const isLive = process.env.DODO_PAYMENTS_ENVIRONMENT === \"live_mode\";\n  return new DodoPayments({\n    bearerToken: apiKey,\n    ...(isLive ? {} : { environment: \"test_mode\" as const }),\n    ...options,\n  });\n}\n\nfunction compareEntitlementPlans(\n  a: { planKey: string; validUntil: number },\n  b: { planKey: string; validUntil: number },\n): number {\n  const tierDelta = getFeaturesForPlan(a.planKey).tier - getFeaturesForPlan(b.planKey).tier;\n  if (tierDelta !== 0) return tierDelta;\n  const rankDelta = (PLAN_PRECEDENCE[a.planKey] ?? 0) - (PLAN_PRECEDENCE[b.planKey] ?? 0);\n  if (rankDelta !== 0) return rankDelta;\n  return a.validUntil - b.validUntil;","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/convex/payments/billing.ts#L36-L72","documentation":"Structured ConvexError thrown by getDodoClient when process.env.DODO_API_KEY is unset at call time. It is a configuration guard: the billing module cannot construct the DodoPayments REST SDK client without the canonical API key, so any billing, portal, or subscription action that needs the client fails before any network call.","triggerScenarios":"Thrown at convex/payments/billing.ts:53 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Set DODO_API_KEY in the deployment environment (Convex/Cloud env vars) with a valid DodoPayments key","Redeploy or restart the Convex deployment after setting the variable so the runtime picks it up","Confirm the variable is present in every environment (prod, preview, dev) that runs billing actions"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}