Self-hosted dashboard fails at login with "Missing value for Stripe(): apiKey should be a string"
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 3k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 73
Description
To Reproduce
- Run a self-hosted / development instance from
canary(noNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYset — it isn't inapps/dokploy/.env.example). - Log in.
- The dashboard fails to render.
Runtime IntegrationError
Missing value for Stripe(): apiKey should be a string.
Current vs. Expected behavior
Current: a self-hosted instance can't get past login. Setting NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY to any non-empty placeholder unblocks it, which is what identifies the cause.
Expected: a self-hosted instance never touches Stripe. IS_CLOUD / settings.isCloud is false, so nothing billing-related should be reachable.
What causes it
The import chain from the dashboard entry point is fully static:
apps/dokploy/pages/dashboard/home.tsx:13
→ components/dashboard/onboarding/onboarding-wizard.tsx:21
→ components/dashboard/onboarding/steps/plan-step.tsx:14
and plan-step.tsx calls Stripe at module scope, not inside the component:
const stripePromise = loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
);
The guard inside the wizard is a runtime one:
const { data: isCloud = true } = api.settings.isCloud.useQuery();
const visibleStepIds = isCloud ? ... : ...;
It decides which steps render. It cannot prevent the module from being imported, so loadStripe(undefined) runs on every self-hosted instance regardless. Stripe.js then throws IntegrationError because the key isn't a string.
components/dashboard/settings/billing/show-billing.tsx:45 does the same thing at module scope, and plan-step.tsx imports from it, so there are two paths to the same call.
Introduced by 2e2e0c8c2 ("feat: cloud onboarding wizard, billing trial card, and post-checkout server setup"). Server-side billing is unaffected — getBillingStatus returns early on !IS_CLOUD before creating a Stripe client. This is client-side only.
Possible fixes, in rough order of least invasive: move loadStripe inside the component (or a useMemo) so it only runs when the plan step actually renders; or lazy-load PlanStep behind the isCloud check; or make the call tolerant of a missing key.
Provide environment information
- Dokploy
v0.30.5(canaryat1572008c) - Self-hosted, Docker, macOS host, Node 26, Next.js 16.3.0 (Turbopack)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYunset, as per.env.example
Which area(s) are affected? (Select all that apply)
Dashboard / UI
Are you deploying the applications where Dokploy is installed or on a remote server?
Dokploy Server
Additional context
Found while testing a DNS provider branch rebased on canary; it reproduces on plain canary and has nothing to do with that work. Worth flagging because it affects every self-hosted instance on this version, and the error message points at Stripe rather than at the onboarding wizard, which makes it easy to misattribute.
Will you send a PR to fix it?
No
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the static imports from apps/dokploy/pages/dashboard/home.tsx through components/dashboard/onboarding/onboarding-wizard.tsx and components/dashboard/onboarding/steps/plan-step.tsx; also inspect the module-scope Stripe call in components/dashboard/settings/billing/show-billing.tsx. Reproduce login with NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY unset, then verify that self-hosted dashboard rendering no longer invokes Stripe while cloud billing and onboarding remain available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nextjs, typescript
- Domain
- cloud, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 74/100