{"record":{"id":"03cb25f0c3930a2a","repo":"router-for-me/CLIProxyAPI","slug":"kimi-failed-to-create-device-code-request-w","errorCode":null,"errorMessage":"kimi: failed to create device code request: %w","messagePattern":"kimi: failed to create device code request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/kimi/kimi.go","lineNumber":187,"sourceCode":"// commonHeaders returns headers required for Kimi API requests.\nfunc (c *DeviceFlowClient) commonHeaders() map[string]string {\n\treturn map[string]string{\n\t\t\"X-Msh-Platform\":     \"CLIProxyAPI\",\n\t\t\"X-Msh-Version\":      buildinfo.Version,\n\t\t\"X-Msh-Device-Name\":  getHostname(),\n\t\t\"X-Msh-Device-Model\": getDeviceModel(),\n\t\t\"X-Msh-Device-Id\":    c.deviceID,\n\t}\n}\n\n// RequestDeviceCode initiates the device flow by requesting a device code from Kimi.\nfunc (c *DeviceFlowClient) RequestDeviceCode(ctx context.Context) (*DeviceCodeResponse, error) {\n\tdata := url.Values{}\n\tdata.Set(\"client_id\", kimiClientID)\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, kimiDeviceCodeURL, strings.NewReader(data.Encode()))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"kimi: failed to create device code request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\treq.Header.Set(\"Accept\", \"application/json\")\n\tfor k, v := range c.commonHeaders() {\n\t\treq.Header.Set(k, v)\n\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)","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/kimi/kimi.go#L169-L205","documentation":"http.NewRequestWithContext failed building the RFC 8628 device-authorization POST to https://auth.kimi.com/api/oauth/device_authorization. Method and URL are hardcoded constants, so failure effectively means a nil or already-canceled context was passed into RequestDeviceCode. It fails before any network activity, unlike 219.","triggerScenarios":"Kimi login initiated with a context canceled by an early timeout or shutdown; embedding code passing a finished request context into the device flow; (theoretical) corrupted kimiDeviceCodeURL constant.","commonSituations":"Wrapper scripts with very short auth timeouts canceling before the first POST; SDK integrations reusing a stale context; not seen in normal CLI usage.","solutions":["Check errors.Is(err, context.Canceled) on the result to confirm prior cancellation.","Use a fresh context with a timeout sized for the whole device flow (user approval can take minutes).","When embedding, ensure the device-flow context is independent of any single HTTP request lifetime."],"exampleFix":"// before\ntok, err := c.RequestDeviceCode(shortReqCtx)\n\n// after\nflowCtx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)\ndefer cancel()\ntok, err := c.RequestDeviceCode(flowCtx)","handlingStrategy":"validation","validationCode":"if ctx == nil || ctx.Err() != nil {\n    return errors.New(\"device flow context already dead; pass a fresh context\")\n}\ndc, err := c.RequestDeviceCode(ctx)","typeGuard":null,"tryCatchPattern":"dc, err := c.RequestDeviceCode(ctx)\nif err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n        // rebuild context; device flow needs minutes, not seconds\n    }\n}","preventionTips":["Size device-flow context timeouts for human approval time (minutes).","Keep the device-flow context independent of HTTP request lifetimes."],"tags":["oauth","kimi","context","device-flow","http-request"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}