koala73/worldmonitor · error · ConvexError

Checkout failed: ${msg}

Error message

Checkout failed: ${msg}

What it means

Catch-all in `_createCheckoutSession`: any error thrown by the Dodo Payments provider call (after bounded rate-limit retry) is logged server-side as `[checkout] createCheckout failed` and re-thrown as a ConvexError with the underlying message interpolated. This preserves the public action's contract of rejecting provider failures via the error channel.

Source

Thrown at convex/payments/checkout.ts:330

            `[checkout] Dodo 429 for user=${user.userId} product=${args.productId}; retrying in ${delayMs}ms`,
          ),
      },
    );
    if (isCheckoutRateLimitedOutcome(result)) {
      console.warn(
        `[checkout] Dodo rate limited checkout creation for user=${user.userId} product=${args.productId} after bounded retry (<=${CHECKOUT_RATE_LIMIT_MAX_ATTEMPTS} attempts); retry after ${result.retryAfterSeconds}s`,
      );
      return result;
    }
    return anonymousClaimToken
      ? { ...result, anonymous_claim_token: anonymousClaimToken }
      : result;
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    console.error(
      `[checkout] createCheckout failed for user=${user.userId} product=${args.productId}: ${msg}`,
    );
    throw new ConvexError(`Checkout failed: ${msg}`);
  }
}

// ---------------------------------------------------------------------------
// Public action: authenticated via Convex/Clerk auth
// ---------------------------------------------------------------------------

export const createCheckout = action({
  args: {
    productId: v.string(),
    returnUrl: v.optional(v.string()),
    discountCode: v.optional(v.string()),
    referralCode: v.optional(v.string()),
    // "Start a new checkout anyway" — skips ONLY the pending-payment guard
    // (#4438). The subscription guard still applies.
    bypassPendingGuard: v.optional(v.boolean()),
  },
  handler: async (ctx, args) => {

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Inspect the interpolated `msg` and the server log line `[checkout] createCheckout failed for user=... product=...: <msg>` for the root cause
  2. Verify the productId resolves via resolveProductToPlan in the product catalog
  3. Validate discountCode/referralCode before submitting if applicable
  4. Retry once if the msg indicates a transient network/provider error; escalate if persistent
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate product/discount inputs before checkout to reduce provider failures.
const product = resolveProductToPlan(args.productId);
if (!product) { /* block: unknown productId */ }

Try / catch

try {
  const result = await convex.action(api.payments.checkout.createCheckout, args);
} catch (err) {
  // err.message starts with 'Checkout failed: ' + provider detail
  // inspect the server log [checkout] createCheckout failed for user=... product=...
  if (/rate/i.test(err.message)) { /* back off */ } else { /* surface detail */ }
}

Prevention

When it happens

Trigger: The Dodo checkout-creation call raises: invalid productId, expired/invalid discount or referral code, Dodo API error response, network/transport failure, or a non-Error exception. The interpolated `msg` carries the specifics.

Common situations: Invalid productId not in the catalog; expired discount code; Dodo provider outage; malformed customer data; rate-limit retries already exhausted and re-surfaced here.

Related errors


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/bc717efe0c15b856. Report an issue: GitHub.