sipeed/picoclaw · warning
authentication timed out after 5 minutes
Error message
authentication timed out after 5 minutes
What it means
The whole interactive login window expired: neither the loopback browser callback nor the manual-paste channel delivered a code within 5 minutes (oauth.go:183, time.After(5 * time.Minute)). The OAuth code is short-lived anyway, so after this timeout the flow must restart from a fresh PKCE/state pair.
Source
Thrown at pkg/auth/oauth.go:183
return ExchangeCodeForTokens(cfg, result.code, pkce.CodeVerifier, redirectURI)
case manualInput := <-manualCh:
if manualInput == "" {
return nil, fmt.Errorf("manual input canceled")
}
// Extract code from URL if it's a full URL
code := manualInput
if strings.Contains(manualInput, "?") {
u, err := url.Parse(manualInput)
if err == nil {
code = u.Query().Get("code")
}
}
if code == "" {
return nil, fmt.Errorf("could not find authorization code in input")
}
return ExchangeCodeForTokens(cfg, code, pkce.CodeVerifier, redirectURI)
case <-time.After(5 * time.Minute):
return nil, fmt.Errorf("authentication timed out after 5 minutes")
}
}
func oauthCallbackRedirectURI(port int) string {
return fmt.Sprintf("http://localhost:%d/auth/callback", port)
}
func oauthCallbackHandler(state string, resultCh chan<- callbackResult) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/auth/callback", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("state") != state {
resultCh <- callbackResult{err: fmt.Errorf("state mismatch")}
http.Error(w, "State mismatch", http.StatusBadRequest)
return
}
code := r.URL.Query().Get("code")
if code == "" {View on GitHub (pinned to 49183d7e8d)
Solutions
- Re-run the login command and complete it promptly — a fresh state/PKCE pair is generated each run
- If no browser opened, manually open the printed authorization URL immediately
- Open the auth URL on a phone/other machine right away so the redirect lands within the window
- For truly slow flows, prefer the device-code flow (RequestDeviceCode) which polls with the server-returned interval
Defensive patterns
Strategy: retry
Try / catch
cred, err := auth.LoginBrowserWithOptions(cfg, opts)
if err != nil && strings.Contains(err.Error(), "authentication timed out") {
fmt.Println("5-minute window expired — restarting login; complete consent promptly")
cred, err = auth.LoginBrowserWithOptions(cfg, opts) // fresh state/PKCE each run
}
if err != nil { return err } Prevention
- Complete consent within the 5-minute window; restart if it lapses
- Open the printed auth URL immediately in headless setups
- Use the device-code flow for slow MFA/SSO journeys
When it happens
Trigger: User starts login, gets distracted; browser fails to open (no xdg-open/open on the host) so the user never sees the auth page; user completes consent only after 5+ minutes of fiddling with login/2FA.
Common situations: Headless boxes missing a browser opener; slow SSO/MFA journeys; SSH sessions where the printed URL had to be carried to another machine and the round trip exceeded 5 minutes.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- manual input canceled
- starting callback server on port %d: %w
- could not find authorization code in input
- state mismatch
- no code received: %s
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/bc7558d1f887a645.
Report an issue: GitHub.