router-for-me/CLIProxyAPI · error
timeout waiting for OAuth callback
Error message
timeout waiting for OAuth callback
What it means
Thrown by WaitForCallback when the local OAuth callback HTTP server does not receive the provider redirect within the caller-supplied timeout. The function blocks on a select over the result channel, the error channel, and time.After(timeout); if the browser never hits the callback URL before the deadline, the timeout branch wins. It means the authorization leg of the flow (user login + redirect) never completed, not that the token exchange failed.
Source
Thrown at internal/auth/codex/oauth_server.go:154
// WaitForCallback waits for the OAuth callback with a timeout.
// It blocks until either an OAuth result is received, an error occurs,
// or the specified timeout is reached.
//
// Parameters:
// - timeout: The maximum time to wait for the callback
//
// Returns:
// - *OAuthResult: The OAuth result if successful
// - error: An error if the callback times out or an error occurs
func (s *OAuthServer) WaitForCallback(timeout time.Duration) (*OAuthResult, error) {
select {
case result := <-s.resultChan:
return result, nil
case err := <-s.errorChan:
return nil, err
case <-time.After(timeout):
return nil, fmt.Errorf("timeout waiting for OAuth callback")
}
}
// handleCallback handles the OAuth callback endpoint.
// It extracts the authorization code and state from the callback URL,
// validates the parameters, and sends the result to the waiting channel.
//
// Parameters:
// - w: The HTTP response writer
// - r: The HTTP request
func (s *OAuthServer) handleCallback(w http.ResponseWriter, r *http.Request) {
log.Debug("Received OAuth callback")
// Validate request method
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Re-run the login flow and complete the browser prompt promptly, keeping the callback port reachable.
- Verify the callback port is free and matches what the flow registered: `lsof -i :<callback-port>` and re-run with `--oauth-callback-port <same-port>`.
- On SSH/containers, forward the callback port (e.g. `ssh -L 1455:127.0.0.1:1455`) or run the login on a machine with a browser.
- Disable proxies for 127.0.0.1/localhost (NO_PROXY) so the browser redirect is not swallowed.
- Increase the timeout value passed to WaitForCallback if the environment is known to be slow.
Example fix
// before
result, err := server.WaitForCallback(2 * time.Minute)
// after
result, err := server.WaitForCallback(5 * time.Minute)
if err != nil {
log.Errorf("oauth callback not received: %v; check the callback port is reachable from your browser", err)
} Defensive patterns
Strategy: retry
Validate before calling
// Before starting the flow, confirm the callback port is actually free
ln, err := net.Listen("tcp", ":1455")
if err != nil {
log.Fatalf("callback port busy: %v", err)
}
_ = ln.Close() // OAuthServer will re-bind it Try / catch
result, err := server.WaitForCallback(5 * time.Minute)
if err != nil {
if strings.Contains(err.Error(), "timeout waiting for OAuth callback") {
// restart the whole flow: shutdown server, regenerate PKCE, re-open browser
log.Warnf("login timed out; restarting OAuth flow")
continue // next loop iteration
}
return err
} Prevention
- Always run the login command in an environment where a browser can reach 127.0.0.1 on the callback port.
- Forward the callback port when working over SSH.
- Complete the browser prompt promptly; do not leave the flow half-finished.
- Ensure only one login flow owns the callback port at a time.
When it happens
Trigger: User never opens or completes the login page; browser redirects to a different port than the one the OAuthServer listens on (--oauth-callback-port mismatch); the callback port is occupied by another process so the real server never gets the request; headless/SSH environment with no browser to reach 127.0.0.1; firewall or browser extension blocks the localhost redirect; timeout passed by the caller is too short for slow interactive login.
Common situations: Running cli-proxy-api login inside a container or over SSH without port forwarding; two login attempts racing for the same callback port; corporate proxy stripping the redirect; user walks away from the browser past the timeout (commonly 2-5 minutes).
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- callback_timeout
- port %d is already in use
- failed to create token request: %w
- token exchange request failed: %w
- failed to read token response: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/a8100c2a5593f178.
Report an issue: GitHub.