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
- Retry after confirming connectivity: curl https://auth.kimi.com/api/oauth/token (expect 4xx, proving reachability)
- Open firewall/egress for auth.kimi.com in addition to api.kimi.com — refresh hits the auth host
- 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
- Allow egress to auth.kimi.com, not just api.kimi.com
- Schedule refresh retries with backoff instead of tight loops
- Rely on singleflight — do not fan out parallel refresh calls
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
- kimi: failed to read refresh response: %w
- kimi: failed to read device code response: %w
- kimi: token request failed: %w
- kimi: failed to read token response: %w
- kimi: failed to create refresh request: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/20731fa3b482c00d.
Report an issue: GitHub.