router-for-me/CLIProxyAPI · error
kimi: failed to parse refresh response: %w
Error message
kimi: failed to parse refresh response: %w
What it means
The refresh endpoint returned 200 but the body failed to parse as the expected token JSON. Same failure class as error 228, on the refresh path: an HTML challenge page, truncated body, or changed response schema will trip json.Unmarshal here.
Source
Thrown at internal/auth/kimi/kimi.go:417
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))
}
var tokenResp struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
ExpiresIn float64 `json:"expires_in"`
Scope string `json:"scope"`
}
if err = json.Unmarshal(bodyBytes, &tokenResp); err != nil {
return nil, fmt.Errorf("kimi: failed to parse refresh response: %w", err)
}
if tokenResp.AccessToken == "" {
return nil, fmt.Errorf("kimi: empty access token in refresh response")
}
var expiresAt int64
if tokenResp.ExpiresIn > 0 {
expiresAt = time.Now().Unix() + int64(tokenResp.ExpiresIn)
}
return &KimiTokenData{
AccessToken: tokenResp.AccessToken,
RefreshToken: tokenResp.RefreshToken,
TokenType: tokenResp.TokenType,
ExpiresAt: expiresAt,
Scope: tokenResp.Scope,
}, nilView on GitHub (pinned to 78f0c4079e)
Solutions
- Log bodyBytes before unmarshal to identify HTML vs truncated vs reshaped JSON
- Retry once — challenge pages are often transient
- If the schema changed, update the anonymous struct at kimi.go:407 or upgrade CLIProxyAPI
Defensive patterns
Strategy: validation
Validate before calling
// In wrappers: cheap pre-check that the 200 body is JSON before parsing
if !bytes.HasPrefix(bytes.TrimSpace(bodyBytes), []byte("{")) {
return nil, fmt.Errorf("kimi: non-JSON refresh response: %.120s", bodyBytes)
} Try / catch
var synErr *json.SyntaxError
if errors.As(err, &synErr) {
// log body; if HTML -> proxy/WAF; if truncated -> retry; if reshaped -> schema drift
} Prevention
- Log raw refresh bodies on parse failure
- Keep auth.kimi.com out of intercepting proxies
- Upgrade CLIProxyAPI when token endpoint schemas change
When it happens
Trigger: WAF/interstitial HTML served with 200 on /api/oauth/token during refresh, truncated response from proxies, Moonshot changes refresh response field names so AccessToken/RefreshToken fields no longer unmarshal as expected.
Common situations: Intercepting proxies on the auth host in long-running deployments, CDN challenge pages hitting background refresh, upstream schema drift after Kimi updates.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- kimi: failed to parse device code response: %w
- kimi: failed to parse token response: %w
- kimi: refresh token is required
- kimi: failed to create refresh request: %w
- kimi: refresh request failed: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/2210461e9909ce8e.
Report an issue: GitHub.