{"record":{"id":"2a3789730b644bfb","repo":"router-for-me/CLIProxyAPI","slug":"kimi-device-code-request-failed-with-status-d","errorCode":null,"errorMessage":"kimi: device code request failed with status %d: %s","messagePattern":"kimi: device code request failed with status (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/kimi/kimi.go","lineNumber":211,"sourceCode":"\t}\n\n\tresp, err := c.httpClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"kimi: device code request failed: %w\", err)\n\t}\n\tdefer func() {\n\t\tif errClose := resp.Body.Close(); errClose != nil {\n\t\t\tlog.Errorf(\"kimi device code: close body error: %v\", errClose)\n\t\t}\n\t}()\n\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"kimi: failed to read device code response: %w\", err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"kimi: device code request failed with status %d: %s\", resp.StatusCode, string(bodyBytes))\n\t}\n\n\tvar deviceCode DeviceCodeResponse\n\tif err = json.Unmarshal(bodyBytes, &deviceCode); err != nil {\n\t\treturn nil, fmt.Errorf(\"kimi: failed to parse device code response: %w\", err)\n\t}\n\n\treturn &deviceCode, nil\n}\n\n// PollForToken polls the token endpoint until the user authorizes or the device code expires.\nfunc (c *DeviceFlowClient) PollForToken(ctx context.Context, deviceCode *DeviceCodeResponse) (*KimiTokenData, error) {\n\tif deviceCode == nil {\n\t\treturn nil, fmt.Errorf(\"kimi: device code is nil\")\n\t}\n\n\tinterval := time.Duration(deviceCode.Interval) * time.Second\n\tif interval < defaultPollInterval {","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/kimi/kimi.go#L193-L229","documentation":"Kimi's device authorization endpoint returned a non-200 HTTP status. The full response body is embedded in the error message, so the server's explanation (rate limit, invalid client, server error) is visible. The request itself is well-formed; failure comes from the server side or the request's client_id.","triggerScenarios":"POST to /api/oauth/device_authorization with the hardcoded client_id 17e5f671-... returns 4xx/5xx: 429 rate limiting from too many login attempts, 4xx if Moonshot invalidates or restricts the client ID, 5xx during auth.kimi.com outages, or Cloudflare-style 403 blocks for datacenter IPs.","commonSituations":"Version drift where Kimi changes or deprecates its OAuth client ID (fix requires updating this repo), repeated login retries triggering rate limits, running the proxy from a cloud IP that Kimi's WAF blocks, auth.kimi.com regional outage.","solutions":["Read the embedded body in the error message — it names the actual cause (e.g. 'rate_limited', 'invalid_client')","If 429: wait the interval indicated (or 60s+) before requesting a new device code instead of retrying in a loop","Update CLIProxyAPI to the latest release — a changed/rotated kimiClientID is fixed upstream in internal/auth/kimi/kimi.go","If blocked (403) from a datacenter/VPN IP, run the login from a residential network or allowed egress IP"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isDeviceCodeStatusErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"device code request failed with status\")\n}","tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"status 429\") {\n        // back off before next login attempt\n        time.Sleep(time.Minute)\n    }\n    return err // body in message carries the server's reason\n}","preventionTips":["Never loop StartDeviceFlow without backoff — 429 compounds","Parse the status out of the message to branch retry vs abort","Update CLIProxyAPI when Moonshot rotates the OAuth client ID"],"tags":["kimi","oauth","device-flow","http","rate-limit"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}