koala73/worldmonitor · error · Error
Authentication unavailable while loading Business Pro seats.
Error message
Authentication unavailable while loading Business Pro seats. Try again.
What it means
Thrown by listBusinessSeats() in src/services/billing.ts when the Convex client and API are available but waitForConvexAuthForUser(userId) returns false while the same Clerk user is still current. That helper waits up to 10 s for the Convex WebSocket auth barrier — the server-confirmed setAuth for this exact userId — and also fails if the barrier was superseded by a newer auth generation. The error means: signed in via Clerk, Convex reachable enough to construct a client, but Convex never confirmed this user's authentication in time, so the businessSeats.listSeats query is not issued.
Source
Thrown at src/services/billing.ts:496
ownerDomain: string | null;
ownerIsCorporateDomain: boolean;
seats: BusinessSeat[];
}
/** List the caller's Business Pro seats. Only the owner sees their own grants. */
export async function listBusinessSeats(): Promise<ListBusinessSeatsResult> {
const userId = getCurrentClerkUser()?.id;
if (!userId) {
return { businessSubscriptionId: null, ownerDomain: null, ownerIsCorporateDomain: false, seats: [] };
}
const client = await getConvexClient();
const api = await getConvexApi();
if (!client || !api) {
return { businessSubscriptionId: null, ownerDomain: null, ownerIsCorporateDomain: false, seats: [] };
}
if (!await waitForConvexAuthForUser(userId)) {
assertAccountStillCurrent(userId, 'loading Business Pro seats');
throw new Error('Authentication unavailable while loading Business Pro seats. Try again.');
}
return settleAccountOperation(
userId,
'loading Business Pro seats',
() => client.query(api.payments.businessSeats.listSeats, {}),
);
}
/** Invite up to 4 same-domain teammates to Business Pro seats. */
export async function inviteBusinessSeats(emails: string[]): Promise<{
invited: Array<{ email: string; grantId: string; status: 'created' | 'already_pending' | 'already_accepted' }>;
}> {
const userId = requireSignedInUserId('invite Business Pro seats');
const client = await getConvexClient();
const api = await getConvexApi();
if (!client || !api) throw new Error('Convex unavailable');
await requireCurrentConvexUser(userId, 'inviting Business Pro seats');
return settleAccountOperation(View on GitHub (pinned to eeab0a219f)
Solutions
- Retry the load once after a short delay — the barrier usually settles just after the timeout, and the second call typically succeeds.
- In DevTools → Network → WS, confirm the wss://…convex.cloud socket connects and authenticates; a failing upgrade points to proxy/VPN interference.
- Verify the Clerk keys and VITE_CONVEX_URL belong to the same deployment pairing (Convex auth configured for this Clerk instance).
- If it reproduces deterministically for one user, check for auth-generation churn: rapid sign-out/sign-in loops that permanently supersede the waited barrier.
Example fix
// before
const seats = await listBusinessSeats();
// after
let seats;
try {
seats = await listBusinessSeats();
} catch (err) {
if (err instanceof Error && err.message.startsWith('Authentication unavailable')) {
await new Promise((r) => setTimeout(r, 1500));
seats = await listBusinessSeats();
} else {
throw err;
}
} Defensive patterns
Strategy: retry
Validate before calling
import { waitForConvexAuthForUser } from '@/services/convex-client';
import { getCurrentClerkUser } from '@/services/clerk';
const userId = getCurrentClerkUser()?.id;
if (!userId) return emptySeats;
if (!await waitForConvexAuthForUser(userId, 15_000)) {
showAuthPendingUi();
return;
}
const seats = await listBusinessSeats(); Try / catch
try {
return await listBusinessSeats();
} catch (err) {
if (err instanceof Error && err.message.startsWith('Authentication unavailable')) {
await delay(1500); // barrier usually settles just past the 10s gate
return await listBusinessSeats();
}
throw err;
} Prevention
- Trigger the seats load only after the Convex auth barrier settles (subscribe to auth-ready rather than racing it at mount).
- Give corporate-network users a WebSocket health hint when the Convex socket fails.
- Distinguish this message from 'Account changed while…' — the first is transient, the second requires restarting the flow.
When it happens
Trigger: Opening the Business Pro seats UI within the first seconds after sign-in on a slow link (barrier not yet settled at the 10 s timeout); Clerk token fetch stalling so setAuth never completes; the Convex WebSocket being blocked or dropped by a corporate proxy/VPN; rapid sign-out/sign-in creating a newer auth generation that invalidates the waited barrier.
Common situations: Slow mobile networks right after login; locked-down enterprise networks that allow HTTPS but break WebSocket upgrades; Clerk dev-instance rate limits delaying token issuance; environments where VITE_CONVEX_URL points at a deployment that rejects the Clerk token (misconfigured auth provider).
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Authentication unavailable while loading MCP clients. Try ag
- REDIS_DOWN
- UNAUTHENTICATED
- Revoke service is temporarily unavailable. Try again in a mo
- HTTP ${response.status}
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/f77fc9e069708bbf.
Report an issue: GitHub.