Skip to content

fix(billing): safely initialize Stripe only when publishable key is present (#5344) - #5442

Open
fliptrigga13 wants to merge 1 commit into
Dokploy:canaryfrom
fliptrigga13:fix/issue-5344-self-hosted-stripe-error
Open

fliptrigga13 wants to merge 1 commit into
Dokploy:canaryfrom
fliptrigga13:fix/issue-5344-self-hosted-stripe-error

Conversation

@fliptrigga13

@fliptrigga13 fliptrigga13 commented Sep 13, 2026

Copy link
Copy Markdown

What is this PR about?

Fixes #5344

Problem

On self-hosted installations, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is not configured (as per apps/dokploy/.env.example and Dockerfile, where Stripe is cloud-only).

However, PlanStep and ShowBilling called loadStripe at module scope:

const stripePromise = loadStripe(
	process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
);

Because the onboarding wizard (apps/dokploy/components/dashboard/onboarding/onboarding-wizard.tsx) is statically imported by apps/dokploy/pages/dashboard/home.tsx, loading the dashboard immediately executes loadStripe(undefined).

Stripe's SDK rejects this at module initialization time with:

Runtime IntegrationError: Missing value for Stripe(): apiKey should be a string.

This crashed the dashboard on login for every self-hosted instance.

Solution

  1. Evaluated stripePromise safely at module scope:
    const stripePromise = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
        ? loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY)
        : null;
    On self-hosted instances, stripePromise is null and loadStripe is never invoked with undefined.
  2. Guarded checkout execution in both PlanStep and ShowBilling so attempting checkout without a configured Stripe key safely alerts via toast notification instead of throwing unhandled rejections.
  3. In cloud environments where NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is present, loadStripe executes normally.

Checklist

  • You created a dedicated branch based on the canary branch.
  • You have read the suggestions in the CONTRIBUTING.md file.
  • You have tested this PR in your local instance:
    • Added unit tests in apps/dokploy/__test__/billing/stripe-initialization.test.ts (3/3 passing tests).

Issues related

Fixes #5344

RetriggerConfidence Score: 4/5

The production fix appears safe to merge, with a non-blocking gap in regression-test effectiveness.

Summary

  • Makes module-level Stripe initialization nullable in onboarding and billing components.
  • Displays an error toast instead of attempting checkout without Stripe.
  • Adds regression tests, although those tests currently exercise local copies rather than production behavior.

Reviews (1) · Last reviewed commit: "fix(billing): safely initialize Stripe o..."

Comment on lines +4 to +8
const createStripeLoader = (loadStripeMock: (key: string) => Promise<any>) => {
return (publishableKey?: string) => {
return publishableKey ? loadStripeMock(publishableKey) : null;
};
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Tests duplicate production logic

These tests recreate the Stripe initialization and checkout guards locally instead of importing or exercising either changed production module. Reverting or breaking the guards in PlanStep or ShowBilling would therefore leave all three tests passing, so CI does not protect against this dashboard crash returning. Extract the initialization behavior into an imported helper or test the production modules with loadStripe mocked. The checkout handler at lines 53–60 has the same problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Self-hosted dashboard fails at login with "Missing value for Stripe(): apiKey should be a string"

1 participant