router-for-me/CLIProxyAPI · warning

kimi: context cancelled: %w

Error message

kimi: context cancelled: %w

What it means

The polling loop in PollForToken detected that its context was cancelled (or its deadline exceeded) while waiting for the user to complete authorization. The wrapped ctx.Err() is context.Canceled or context.DeadlineExceeded. No token was obtained; the device code itself may still be valid until it expires server-side.

Source

Thrown at internal/auth/kimi/kimi.go:247

	if interval < defaultPollInterval {
		interval = defaultPollInterval
	}

	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
		}
	}

	ticker := time.NewTicker(interval)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return nil, fmt.Errorf("kimi: context cancelled: %w", ctx.Err())
		case <-ticker.C:
			if time.Now().After(deadline) {
				return nil, fmt.Errorf("kimi: device code expired")
			}

			token, pollErr, shouldContinue := c.exchangeDeviceCode(ctx, deviceCode.DeviceCode)
			if token != nil {
				return token, nil
			}
			if !shouldContinue {
				return nil, pollErr
			}
			// Continue polling
		}
	}
}

// exchangeDeviceCode attempts to exchange the device code for an access token.

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. If the user cancelled intentionally, no fix needed — re-run login to start a fresh device flow
  2. If DeadlineExceeded, give the context passed to PollForToken a deadline >= deviceCode.ExpiresIn (or the 15-minute maxPollDuration)
  3. Ensure the ctx passed to WaitForAuthorization is not derived from a short-lived request scope; use a dedicated context for interactive login

Example fix

// before
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // too short for user to authorize
k.WaitForAuthorization(ctx, deviceCode)

// after
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // cancel only on user interrupt
k.WaitForAuthorization(ctx, deviceCode)
Defensive patterns

Strategy: validation

Validate before calling

// Give interactive login its own long-lived context before polling
if _, ok := ctx.Deadline(); !ok {
    var cancel context.CancelFunc
    ctx, cancel = context.WithTimeout(ctx, 16*time.Minute)
    defer cancel()
}

Try / catch

if err != nil && errors.Is(err, context.Canceled) {
    // user aborted: clean up UI state, do not report as a bug
}

Prevention

When it happens

Trigger: Caller of WaitForAuthorization/PollForToken cancels the ctx (user hits Ctrl-C during the 'visit this URL' wait), a parent context with a deadline shorter than the 15-minute maxPollDuration, server shutdown while a login is in progress.

Common situations: CLI login command with its own timeout shorter than user takes to authorize, TUI/manager cancelling in-flight logins on restart, context propagated from an HTTP request that times out.

Related errors


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