router-for-me/CLIProxyAPI · error

kimi: refresh request failed: %w

Error message

kimi: refresh request failed: %w

What it means

The HTTP round trip for the token refresh POST to /api/oauth/token failed at the transport level (DNS, connection, TLS). Note the refresh runs under singleflight (kimiRefreshGroup) with context.WithoutCancel, so concurrent refreshes share one attempt; if that attempt has a network error, all waiters see it.

Source

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

func (c *DeviceFlowClient) refreshTokenSingleFlight(ctx context.Context, refreshToken string) (*KimiTokenData, error) {
	data := url.Values{}
	data.Set("client_id", kimiClientID)
	data.Set("grant_type", "refresh_token")
	data.Set("refresh_token", refreshToken)

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, kimiTokenURL, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, fmt.Errorf("kimi: failed to create refresh request: %w", err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", "application/json")
	for k, v := range c.commonHeaders() {
		req.Header.Set(k, v)
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("kimi: refresh request failed: %w", err)
	}
	defer func() {
		if errClose := resp.Body.Close(); errClose != nil {
			log.Errorf("kimi refresh token: close body error: %v", errClose)
		}
	}()

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("kimi: failed to read refresh response: %w", err)
	}

	if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
		return nil, fmt.Errorf("kimi: refresh token rejected (status %d)", resp.StatusCode)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("kimi: refresh failed with status %d: %s", resp.StatusCode, string(bodyBytes))

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Retry after confirming connectivity: curl https://auth.kimi.com/api/oauth/token (expect 4xx, proving reachability)
  2. Open firewall/egress for auth.kimi.com in addition to api.kimi.com — refresh hits the auth host
  3. Check DNS resolution inside the container/host if failures cluster
Defensive patterns

Strategy: retry

Validate before calling

if _, err := net.DialTimeout("tcp", "auth.kimi.com:443", 3*time.Second); err != nil {
    // egress to the auth host is down; skip refresh attempt this cycle
}

Type guard

func isKimiNetErr(err error) bool {
    var netErr net.Error
    return errors.As(err, &netErr)
}

Try / catch

if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) {
        time.Sleep(backoff) // refresh again next cycle; token may still be valid
    }
}

Prevention

When it happens

Trigger: Network outage or DNS failure for auth.kimi.com at the moment a stored token crossed the 5-minute expiry threshold and auto-refresh fired; TLS interception failure; connection refused during auth.kimi.com maintenance.

Common situations: Server process running where egress is flaky, transient DNS problems in Kubernetes/containers, firewall rules blocking auth.kimi.com while allowing api.kimi.com.

Related errors


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