koala73/worldmonitor · error
Authenticated account changed during push setup
Error message
Authenticated account changed during push setup
What it means
Thrown by assertExpectedAccount() in src/services/push-notifications.ts, which guards every step of authFetch and subscribeToPush. The flow captures an expectedUserId when it starts; if Clerk's current user (getCurrentClerkUser()?.id) no longer matches at any checkpoint, the operation aborts. This prevents registering a push subscription — which carries browser-level credentials — against the wrong user's row after a mid-flow account switch.
Source
Thrown at src/services/push-notifications.ts:99
auth: string;
userAgent: string;
}
function subscriptionToPayload(sub: PushSubscription): SubscriptionPayload | null {
const p256dh = arrayBufferToBase64(sub.getKey('p256dh'));
const auth = arrayBufferToBase64(sub.getKey('auth'));
if (!p256dh || !auth || !sub.endpoint) return null;
return {
endpoint: sub.endpoint,
p256dh,
auth,
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent.slice(0, 200) : '',
};
}
function assertExpectedAccount(expectedUserId?: string): void {
if (expectedUserId && getCurrentClerkUser()?.id !== expectedUserId) {
throw new Error('Authenticated account changed during push setup');
}
}
async function authFetch(
path: string,
init: RequestInit,
expectedUserId?: string,
): Promise<Response> {
assertExpectedAccount(expectedUserId);
const token = await getClerkToken();
if (!token) throw new Error('Not authenticated');
assertExpectedAccount(expectedUserId);
return fetch(path, {
...init,
headers: {
'Content-Type': 'application/json',
...(init.headers ?? {}),
Authorization: `Bearer ${token}`,View on GitHub (pinned to eeab0a219f)
Solutions
- Discard the in-flight flow entirely and restart it with the new user's id — never resume a crossed flow.
- Pass expectedUserId from the component that owns the current session (re-read at flow start), not a value cached across renders.
- Subscribe to Clerk user-change events and cancel/abort pending push setup on change.
- On catch, re-check getCurrentClerkUser()?.id and re-anchor the UI to the new session before retrying.
Example fix
// before
await subscribeToPush(capturedUserId);
// after
try {
await subscribeToPush(capturedUserId);
} catch (err) {
if (err instanceof Error && err.message === 'Authenticated account changed during push setup') {
const currentId = getCurrentClerkUser()?.id;
if (currentId) await subscribeToPush(currentId);
return;
}
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
import { getCurrentClerkUser } from '@/services/clerk';
const expectedUserId = getCurrentClerkUser()?.id;
if (!expectedUserId) return;
await subscribeToPush(expectedUserId); // captured at flow start, re-checked by every checkpoint Type guard
function isAccountSwitchAbort(err: unknown): boolean {
return err instanceof Error && err.message === 'Authenticated account changed during push setup';
} Try / catch
try {
await subscribeToPush(expectedUserId);
} catch (err) {
if (isAccountSwitchAbort(err)) {
cancelPushSetup(); // discard the crossed flow entirely
const currentId = getCurrentClerkUser()?.id;
if (currentId) restartPushSetup(currentId);
return;
}
throw err;
} Prevention
- Capture expectedUserId at flow start from the live session, never from stale component props.
- Abort in-flight push setup on Clerk user-change events.
- Never resume a crossed-account flow — restart it anchored to the new user.
When it happens
Trigger: User signs out and signs in as another account in a different tab while the push-enable flow is between its checkpoints; an account switcher changes the Clerk user during the await of getClerkToken(); a component re-invokes subscribeToPush with a stale expectedUserId captured before the switch.
Common situations: Shared machines where users swap accounts with settings tabs open; multi-account QA workflows; Clerk session events firing mid-subscription on slow networks.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Sign in to view your brief.
- Not authenticated
- MCP_INTERNAL_HMAC_SECRET not configured
- HTTP ${response.status}
- PRO_REQUIRED
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/be37341bed6b48a0.
Report an issue: GitHub.