Skip to content

Conversation

@Ephem
Copy link
Member

@Ephem Ephem commented Feb 11, 2026

Description

This PR fixes a bug that was introduced when we migrated to useSyncExternalStore. The bug is that when switching orgs and navigating to a new page, the current page re-rendered with the new organization before the navigation, which can cause problems.

Alternative solution: #7815

Compared to that solution, this touches more code, but is scoped to only block updateClient from emitting for the specific setActive call that triggered it, it does not block all updateClient calls to keep the splash radius as small as possible.

We want to refactor this more heavily to have better guarantees, but now is not the time.

I went with a version where a __internal_touch() does not call updateClient and instead returns a client resource, expecting the caller to then call updateClient with the result. updateClient now takes an option to skip emitting.

If we want to refactor further in the future, this approach let's us move the updateClient call around, and also do things with the intermediary client if necessary.

Another version would be to thread a skipUiEmit option all the way through the base resource calls, but in total that's 6 stacks deep and couples UI concerns to resources in a way I did not like.

UPDATE

I found the same bug applied for signing out. I added two tests for this, single session and multi session.

The issue for signOut was that the session removal ran before setTransitiveState, which like the above bug triggered an updateClient which emitted.

Since this flow was simpler I opted for a simpler fix, to move the setTransitiveState to before the session removal. When updateClient is called, the if (this.session) guard detects there is no current session and skips the updateAccessors call. It still emits, but with the transitive state. Later when updateAccessors is called during the signOut, this converts the undefined to null and we are now in a correctly signed out case.

I have verified these fixes works in the dashboard.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added Organization switcher and User switcher pages with an "Emission log" view showing navigation/state entries.
  • Bug Fixes

    • Improved authentication state synchronization to avoid premature emissions during organization or user switches and navigations.
  • Tests

    • Added integration tests validating emission behavior when switching organizations and users across navigation.
  • Chores

    • Recorded a patch release entry to trigger a version update.

@vercel
Copy link

vercel bot commented Feb 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Feb 12, 2026 11:52am

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 11, 2026

🦋 Changeset detected

Latest commit: 68c42f2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@clerk/clerk-js Patch
@clerk/chrome-extension Patch
@clerk/expo Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

The PR adds an __internal_dangerouslySkipEmit option to updateClient, a new internal Session.__internal_touch() that performs a server-side touch and can return a piggybacked ClientResource without updating the client, and a skipUpdateClient fetch option. The setActive flow was refactored to be navigation-aware and to use the new touch/updateClient patterns. It also adds Next.js App Router pages and client layouts (emission logs), integration tests for transitive state, unit tests, and a changeset for a patch release.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(clerk-js): Fix broken transitive state for org switch and signout' directly describes the main change addressing transitive state issues during organization switching and signout operations.
Linked Issues check ✅ Passed The PR successfully addresses USER-4666 by preventing premature organization-change emissions before undefined emissions during org switches through internal __internal_touch() and skip-emission mechanisms.
Out of Scope Changes check ✅ Passed All changes are scoped to transitive state fixes: internal touch/skip-emit APIs, clerk-js core updates, session handling, integration tests, and template pages for testing—all directly supporting the stated objectives.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 11, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7823

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7823

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7823

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7823

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7823

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7823

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7823

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7823

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7823

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7823

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@7823

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7823

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7823

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7823

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7823

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7823

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7823

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7823

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7823

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7823

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7823

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7823

commit: 68c42f2

@Ephem Ephem changed the title fix(clerk-js): Fix broken transitive state when switching organization fix(clerk-js): Fix broken transitive state for org switch and signout Feb 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants