router-for-me/CLIProxyAPI · error
xai device code expired
Error message
xai device code expired
What it means
The local deadline computed for the device code (from its expires_in, with fallbacks) has passed and at least one poll attempt was already made, so PollForToken stops polling. This is the client-side expiry of the OAuth device code: the user never completed authorization in time.
Source
Thrown at internal/auth/xai/xai.go:238
if deviceCode.ExpiresIn > 0 {
codeDeadline := time.Now().Add(time.Duration(deviceCode.ExpiresIn) * time.Second)
if codeDeadline.Before(deadline) {
deadline = codeDeadline
}
}
// Poll immediately once, then wait between subsequent attempts.
firstAttempt := true
timer := time.NewTimer(0)
defer timer.Stop()
for {
select {
case <-ctx.Done():
return nil, fmt.Errorf("xai device code: context cancelled: %w", ctx.Err())
case <-timer.C:
if !firstAttempt && time.Now().After(deadline) {
return nil, fmt.Errorf("xai device code expired")
}
firstAttempt = false
token, pollErr, nextInterval, shouldContinue := a.exchangeDeviceCode(ctx, tokenEndpoint, deviceCode.DeviceCode, interval)
if token != nil {
return token, nil
}
if !shouldContinue {
return nil, pollErr
}
interval = nextInterval
timer.Reset(interval)
}
}
}
// exchangeDeviceCode attempts to exchange a device code for tokens.
// Returns (token, error, nextInterval, shouldContinue).View on GitHub (pinned to 78f0c4079e)
Solutions
- Restart the flow: request a fresh device code and complete authorization promptly
- Use verification_uri_complete (pre-filled code) or auto-open the browser to reduce user delay
- Verify the expires_in units and clock skew if codes seem to expire instantly
Defensive patterns
Strategy: retry
Try / catch
tokenData, err := auth.WaitForAuthorization(ctx, deviceCode)
if err != nil && strings.Contains(err.Error(), "device code expired") {
log.Info("device code expired; requesting a new one")
deviceCode, err = auth.RequestDeviceCode(ctx)
if err != nil { return err }
tokenData, err = auth.WaitForAuthorization(ctx, deviceCode)
} Prevention
- Open the verification URL immediately after issuance (auto-open browser or print URI)
- Use verification_uri_complete so the code is pre-filled
- Bound total wait time to the code lifetime and restart cleanly on expiry
When it happens
Trigger: User does not visit the verification URI and enter the user_code before the code's expiry; authorization completes but the user takes longer than expires_in.
Common situations: Unattended/headless machine where the browser never opens; user steps away during the interactive step; expiry misparsed (e.g. expires_in in ms vs s) making the deadline too short.
Related errors
- kimi: device code expired
- xai device code: response missing device_code
- xai device code: response missing user_code
- xai device code: response missing verification URI
- xai device authorization denied
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/40322c584972afb8.
Report an issue: GitHub.