[@clerk/clerk-js] <SignUp/> sends 2 verification code emails per sign-up: both POST /sign_ups and POST /prepare_verification trigger email send (Flutter analog #117)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.8k
- Forks
- 472
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 189
Description
Preflight
- I have looked into the Readme, Contributing docs and existing issues
- I have reviewed the documentation
Description
The prebuilt <SignUp/> widget from @clerk/react@6.4.2 sends two verification-code emails for a single sign-up submission. The Network panel shows the widget makes two POST requests during one submit, and both server endpoints trigger a verification email send:
POST /v1/client/sign_ups?__clerk_api_version=2025-11-10—signUp.create({ emailAddress, password })POST /v1/client/sign_ups/<id>/prepare_verification?__clerk_api_version=2025-11-10—signUp.prepareEmailAddressVerification({ strategy: 'email_code' })
The user receives two emails with different codes; the first one is invalidated by the second.
Why this is a real bug (not a duplicate of #887)
This is the prebuilt-widget analog of the documented behavior in #887 (closed 2023-03-03), where Clerk contributor @gkats explained:
the
signIn.create()method will also prepare a verification under the hood when called with a strategy such as "email_code". That's why you get two codes. The first one comes fromsignIn.create()and becomes invalid as soon as the second one is generated. When you callsignIn.create()with a "phone_code", "email_code" or "email_link" strategy you don't need to also prepare the verification afterwards.
That explanation applies symmetrically to signUp.create(): when the application's configured strategy is email_code (Dashboard → User & Authentication → Email, Phone, Username → Email address → ✅ Email verification code), signUp.create() auto-prepares a verification on the server side, and the widget's subsequent explicit prepareEmailAddressVerification call generates a second code.
The #887 resolution was a workaround for custom sign-in flows: omit the strategy from signIn.create(), then call prepareFirstFactor() manually. Users of the prebuilt <SignUp/> widget cannot apply this workaround — the widget controls both calls internally. Rebuilding sign-up as a custom useSignUp() flow defeats the purpose of the prebuilt component.
So either:
- (a) The prebuilt
<SignUp/>widget should detect thatsignUp.create()already initiated verification (returned status with the right verification primed) and skip the redundantprepareEmailAddressVerificationcall; OR - (b)
signUp.create()should NOT auto-prepare a verification (the widget should be the sole driver of when verification preparation happens, matching what the workaround in #887 recommends for custom flows).
For comparison, the same root-cause shape was filed against the Flutter SDK and is the documented behavior there too: clerk/clerk-sdk-flutter#117 (createSignUp + follow-up triggering two emails).
Reproduction
Minimal repro is the prebuilt <SignUp/> widget with password + email_code strategy. No custom code, no useSignUp() flow.
// main.tsx
import { ClerkProvider } from "@clerk/react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ClerkProvider publishableKey={CLERK_KEY}>
<App />
</ClerkProvider>
</StrictMode>
);
// sign-up.tsx
import { SignUp } from "@clerk/react";
export function SignUpPage() {
return (
<SignUp
routing="path"
path="/sign-up"
signInUrl="/sign-in"
/>
);
}
Clerk Dashboard → User & Authentication → Email, Phone, Username → Email address → Verification methods:
- ✅ Email verification code
- ❌ Email verification link
(Only ONE strategy enabled. Issue reproduces regardless — not a dashboard misconfig.)
Steps
pnpm --filter web build && pnpm --filter web preview(prod-build, no StrictMode dev-time side effects)- Open the preview URL, navigate to
/sign-up - DevTools → Network tab → filter
clerk.→ clear log - Enter a fresh email + valid password, click Continue
- Observe Network panel + inbox
Observed
| Endpoint | Method | Count | Status |
|---|---|---|---|
/v1/client/sign_ups?__clerk_api_version=2025-11-10 |
POST | 1 | 200 |
/v1/client/sign_ups/<id>/prepare_verification?__clerk_api_version=2025-11-10 |
POST | 1 | 200 |
/v1/client/sign_ups/<id> |
PATCH | 0 | — |
| Verification emails received within 60s | — | 2 | first invalidated by second per #887 |
Expected
Exactly 1 verification email per sign-up submission from the prebuilt <SignUp/> widget — without requiring users to drop the widget and write a custom useSignUp() flow.
SDK / Environment
@clerk/react:^6.4.2@clerk/clerk-js(transitive, bundled with@clerk/react@6.4.2)- React:
19.0.x+react-dom@19.0.x - Build tool: Vite 5, prod build (
pnpm build && pnpm preview) - Browser: Chrome (latest stable)
- API version (from request URL):
__clerk_api_version=2025-11-10 - Dashboard strategy: Email verification code enabled; Email verification link disabled
Workaround
The workaround documented in #887 — omit strategy from the create() call, then explicitly call the prepare method — requires rebuilding sign-up as a custom useSignUp() flow. This is not viable for users of the prebuilt <SignUp/> component (the widget owns those calls).
No workaround within the prebuilt widget is known.
References
- #887 —
signIn.prepareFirstFactorsending two emails with different codes (closed 2023-03-03; sign-in side; documents the by-designcreate({strategy})auto-prepare behavior) - clerk/clerk-sdk-flutter#117 —
auth.attemptSignUptriggers two verification code emails (Flutter SDK analog of this exact symptom shape) - #4324 — Receiving Twice Email Verification Codes During Sign-In (possibly related, unresolved as of search; sign-in side,
@clerk/nextjs ^5.7.2)
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 with the prebuilt flow and the signUp.create and prepareEmailAddressVerification calls described in the issue; reproduce it with pnpm --filter web build && pnpm --filter web preview and inspect the Network panel. Done means one sign-up submission produces exactly one verification email without requiring a custom useSignUp() flow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- api, authentication, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100