tinyhumansai/openhuman · warning · Error
Timed out waiting for browser sign-in. Try again.
Error message
Timed out waiting for browser sign-in. Try again.
What it means
OAuth connect flow for an MCP server: ConnectAuthModal opens the auth URL in the system browser (openUrl), then polls mcpClientsApi.status() every 2.5s looking for the server's status to become 'connected'. If 180000 ms (3 minutes) elapse first, it throws the localized string behind 'mcp.connectAuth.oauthTimeout' and resets the waiting/busy modal state so the user can retry.
Source
Thrown at app/src/components/channels/mcp/ConnectAuthModal.tsx:297
setBusy(true);
setError(null);
setOauthWaiting(true);
void (async () => {
try {
const url = await mcpClientsApi.oauthBegin(server.server_id);
await openUrl(url);
const started = Date.now();
const poll = async (): Promise<void> => {
const statuses = await mcpClientsApi.status();
const mine = statuses.find(s => s.server_id === server.server_id);
if (mine?.status === 'connected') {
const result = await mcpClientsApi.connect(server.server_id);
onConnected(result.tools ?? []);
onClose();
return;
}
if (Date.now() - started > 180000) {
throw new Error(t('mcp.connectAuth.oauthTimeout'));
}
window.setTimeout(() => {
void poll().catch(handlePollError);
}, 2500);
};
const handlePollError = (err: unknown) => {
setError(err instanceof Error ? err.message : String(err));
setOauthWaiting(false);
setBusy(false);
};
await poll().catch(handlePollError);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
log('oauth failed: %s', msg);
setError(msg);
setOauthWaiting(false);
setBusy(false);
}View on GitHub (pinned to 7491200858)
Solutions
- Click Connect again and complete the browser sign-in promptly - most cases are simply an abandoned browser step
- If sign-in did complete, check the server's status directly (mcpClientsApi.status() / MCP health tab) - a terminal 'error' status means the exchange failed, not that you were too slow
- Verify the backend OAuth callback reached the server (proxy/VPN blocking the redirect is common)
- Only if a legitimate flow consistently needs more than 3 minutes, raise the 180000 constant
Defensive patterns
Strategy: retry
Validate before calling
// Fail fast if the server is already in a terminal state before opening the browser
const statuses = await mcpClientsApi.status();
const mine = statuses.find(s => s.server_id === server.server_id);
if (mine && mine.status !== 'disconnected' && mine.status !== 'error') {
// already connected or connecting - no OAuth round-trip needed
} Try / catch
// distinguish the timeout from transport failures in the poll error handler
const handlePollError = (err: unknown) => {
const msg = err instanceof Error ? err.message : String(err);
if (msg === t('mcp.connectAuth.oauthTimeout')) {
setError(msg); // user-abandonable: offer Connect again
setOauthWaiting(false); // keep the modal open for retry
} else {
setError(msg);
setOauthWaiting(false);
}
setBusy(false);
}; Prevention
- Complete the browser sign-in promptly after Connect - the window is 3 minutes at a 2.5s poll interval
- If sign-in completed but the modal still times out, check mcpClientsApi.status() for a terminal error instead of retrying blindly
- Keep the modal mounted while polling; unmounting abandons the loop without cancelling the server-side flow
When it happens
Trigger: The user never completes (or abandons) the browser sign-in within 3 minutes; or sign-in completes but the server never reaches status 'connected' because the token exchange or redirect failed server-side, so every poll returns a non-connected status until the deadline.
Common situations: User closes the browser tab mid-flow; popup/redirect blocked or corporate proxy strips the callback; backend OAuth exchange fails silently while the modal keeps polling; very slow identity providers or users leaving the modal open in the background.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- oauthAuthReadinessUserMessage(quick.reason)
- mcp.health.opErrorGeneric
- HTTP {} while fetching {} — {}
- secret request {} timed out after {}s
- Socket not connected
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/59954eac4c5192c4.
Report an issue: GitHub.