router-for-me/CLIProxyAPI · warning

xai device code: context cancelled: %w

Error message

xai device code: context cancelled: %w

What it means

The context passed to PollForToken was cancelled or its deadline expired while the poll loop was waiting for user authorization. The select on ctx.Done() aborts the device flow and wraps context.Canceled or context.DeadlineExceeded.

Source

Thrown at internal/auth/xai/xai.go:235

	}

	deadline := time.Now().Add(MaxPollDuration)
	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)
		}
	}
}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Give the device flow its own context with a timeout >= the device code lifetime (typically expires_in from the authorization response)
  2. Derive from context.Background() for interactive flows instead of a request-scoped context
  3. If cancellation was intentional (shutdown), treat this as a clean abort rather than an error

Example fix

// before
tokenData, err := auth.WaitForAuthorization(reqCtx, deviceCode) // reqCtx has 30s deadline

// after
authCtx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
tokenData, err := auth.WaitForAuthorization(authCtx, deviceCode)
Defensive patterns

Strategy: validation

Validate before calling

authCtx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) // >= device code lifetime
defer cancel()
tokenData, err := auth.WaitForAuthorization(authCtx, deviceCode)

Try / catch

tokenData, err := auth.WaitForAuthorization(authCtx, deviceCode)
if err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        // intentional abort or timeout: clean exit, optionally restart flow
        return err
    }
    return err
}

Prevention

When it happens

Trigger: Any cancellation of the ctx given to PollForToken/WaitForAuthorization during the polling window: user Ctrl-C, parent request timeout, shutdown of the calling service.

Common situations: A short HTTP request context reused for an interactive device flow that can legitimately take minutes; orchestrator (e.g. CLI command) timing out; graceful shutdown cancelling in-flight auth.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/dc930fdc873861e7. Report an issue: GitHub.