[Bug]: T3 Connect reports "Your cloud sign-in changed" when the host is just overloaded
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/web
(The failing logic is in packages/client-runtime, which the dropdown does not list. The message is surfaced by the web client, and the timing that triggers it comes from apps/web/src/cloud/managedAuth.tsx.)
Steps to reproduce
- Sign in to T3 Connect and connect to a relay environment from the web client.
- Put the host under heavy CPU/memory load. On a low-power arm64 single-board machine this happens on its own: two or three agent turns plus a build is enough to saturate it.
- Watch the connection status while the machine is pegged.
Expected behavior
While the machine is overloaded the client should report a transient condition, something along the lines of "Reconnecting, the environment is slow to respond", or a timeout, and keep retrying. The sign-in is still valid and nothing about it changed.
Actual behavior
The connection status reads:
Failed to connect. Reconnecting... Reason: Your cloud sign-in changed. Sign in again to authorize the environment.
The sign-in did not change. Signing out and back in does nothing, because there is nothing wrong with the session. The connection recovers on its own once load drops, which is the tell that the message is describing the wrong cause. The practical cost is that the message sends you to fix an auth problem that does not exist instead of the load problem that does.
Impact
Minor bug or occasional failure (misleading diagnosis, self-recovering)
Version or commit
0.0.40. The string is present in the shipped bundle for that release, and the code below was read at main @ de37964db, whose package.json is also 0.0.40.
Environment
Low-power arm64 single-board Linux host, recent Node. Client is the T3 Code web app, connecting through T3 Connect. Nothing here looks hardware specific: any host slow enough to delay Clerk load or the activation promise chain should reproduce it.
Logs or stack traces
Failed to connect. Reconnecting... Reason: Your cloud sign-in changed. Sign in again to authorize the environment.
No stack trace: this is a handled ConnectionBlockedError rendered into the connection status line, not a throw.
Screenshots, recordings, or supporting files
None. The full text of the status line is quoted above.
Workaround
Wait for the load to drop. The connection recovers without any sign-in action.
Diagnosis
The message comes from sessionChanged() in packages/client-runtime/src/authorization/service.ts:224:
const sessionChanged = () =>
new ConnectionBlockedError({
reason: "authentication",
detail: "Your cloud sign-in changed. Sign in again to authorize the environment.",
});
It is raised by assertSession and by getDpopToken whenever cloudSession.identity is None, or is a different object reference than the identity captured when the attempt started. On web, identity is the managedRelaySessionAtom value (apps/web/src/connection/platform.ts:185), and that atom is null until ManagedRelayAuthProvider activates it.
Two things make "identity is not available yet" indistinguishable from "the user signed in as somebody else":
ManagedRelayAuthProvider(apps/web/src/cloud/managedAuth.tsx) bails out while!isLoaded(line 51), and even on the signed-in path it defersactivateManagedRelayAuthenticationbehind a promise chain (activateAfterTransition, line 92). On a loaded machine, Clerk taking longer to load and that promise chain taking longer to drain both widen the window where the atom is stillnullwhile the connection supervisor is already attempting. Every attempt in that window fails withsessionChanged().identityis compared by reference (current.value !== identity). Anything that replaces the session object rather than updating it in place reads as an account change.setManagedRelaySessiondeliberately keeps the object stable across same-account token refreshes, so this is handled for the common case, but theNonecase has no such guard and produces the same message.
Because sessionChanged() is a ConnectionBlockedError, the supervisor moves to blocked and parks. When activation finally lands, managedRelayAccountChanges fires the credentials-changed signal and the supervisor retries, carrying the stale failure into the next connecting state as lastFailure. That is exactly the "Failed to connect. Reconnecting... Reason: ..." shape from connectionStatusText in packages/client-runtime/src/connection/presentation.ts:68, and it explains why the message is shown while the client is in fact recovering.
Likely making it worse on a slow host: CACHED_ENDPOINT_SOCKET_TIMEOUT_MS is 3000 ms (service.ts:82). On an overloaded host the /api/auth/websocket-ticket round trip against a cached endpoint routinely exceeds that, so authorizeDpop discards a perfectly good access token, re-runs the full relay bootstrap and token exchange, and adds load to the host that is already the bottleneck. Each of those extra passes is another chance to hit the None-identity window above.
Suggested fix
Separate "the cloud session is not available yet" from "the cloud session changed":
- When
cloudSession.identityisNoneand there is no evidence of an account switch, fail with aConnectionTransientError(reason: "network", or a newsession-pending) so the supervisor uses normal backoff and the UI says reconnecting rather than telling the user to sign in. - Keep
sessionChanged()for the real case: a captured identity whoseaccountIddiffers from the current one. - Consider comparing
accountIdrather than object reference inassertSession, so an object replacement for an unchanged account cannot produce the message. - Consider whether the 3 s cached-endpoint socket timeout should scale, or whether a timeout there should avoid throwing away the cached access token.
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 packages/client-runtime/src/authorization/service.ts, especially sessionChanged(), assertSession, getDpopToken, and CACHED_ENDPOINT_SOCKET_TIMEOUT_MS, then trace managedAuth.tsx and connection/presentation.ts. Reproduce the delayed activation or overloaded-host case and ensure a pending session produces transient retry messaging while a genuine account change still reports an authentication change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authentication, networking, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100