Description
When accepting an organization invitation via the custom flow documented here, signIn.create({ strategy: 'ticket' }) silently fails if the user already has an active session on the application side.
Steps to reproduce
- User A is signed in and has an active organization (org1)
- User B invites User A to org2 via
organizations.createOrganizationInvitation
- User A clicks the invitation email link
- Clerk FAPI redirects to the app with
__clerk_status=sign_in and __clerk_ticket=<token>
- The custom flow calls
signIn.create({ strategy: 'ticket', ticket: token })
- The call does not throw an error, but the invitation stays
pending — the user is never added to org2
Root cause
Clerk FAPI lives on a different domain than the application (e.g., clerk.example.com vs localhost:3001 or app.example.com). Because of this, FAPI cannot detect the user's existing session cookie and returns __clerk_status=sign_in, indicating the user needs to sign in.
However, on the application side, the user already has an active session. When signIn.create({ strategy: 'ticket' }) is called with this conflicting state (active session + sign_in ticket), it fails silently — no error is thrown, but the invitation is not accepted.
Expected behavior
Either:
signIn.create({ strategy: 'ticket' }) should work correctly even when there's an active session (handling the conflict internally), or
- It should throw a clear error indicating the session conflict so developers can handle it
Workaround
We had to call signOut() before signIn.create() when the user is already signed in:
const { isSignedIn } = useUser();
const { signOut } = useClerk();
if (isSignedIn) {
await signOut();
}
const signInAttempt = await signIn.create({
strategy: "ticket",
ticket: token,
});
Additional context
- The docs example guards the sign_in effect with
|| organization which prevents the effect from running entirely when the user already has an active org — making the documented approach unusable for users who are already members of another organization.
- Next.js 15,
@clerk/nextjs latest
- Tested in development (
localhost) and the behavior is consistent