router-for-me/CLIProxyAPI · error
kimi: failed to create device code request: %w
Error message
kimi: failed to create device code request: %w
What it means
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.
Source
Thrown at internal/auth/kimi/kimi.go:187
// commonHeaders returns headers required for Kimi API requests.
func (c *DeviceFlowClient) commonHeaders() map[string]string {
return map[string]string{
"X-Msh-Platform": "CLIProxyAPI",
"X-Msh-Version": buildinfo.Version,
"X-Msh-Device-Name": getHostname(),
"X-Msh-Device-Model": getDeviceModel(),
"X-Msh-Device-Id": c.deviceID,
}
}
// RequestDeviceCode initiates the device flow by requesting a device code from Kimi.
func (c *DeviceFlowClient) RequestDeviceCode(ctx context.Context) (*DeviceCodeResponse, error) {
data := url.Values{}
data.Set("client_id", kimiClientID)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, kimiDeviceCodeURL, strings.NewReader(data.Encode()))
if err != nil {
return nil, fmt.Errorf("kimi: failed to create device code 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: device code request failed: %w", err)
}
defer func() {
if errClose := resp.Body.Close(); errClose != nil {
log.Errorf("kimi device code: close body error: %v", errClose)
}
}()
bodyBytes, err := io.ReadAll(resp.Body)View on GitHub (pinned to 78f0c4079e)
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.
Example fix
// before tok, err := c.RequestDeviceCode(shortReqCtx) // after flowCtx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) defer cancel() tok, err := c.RequestDeviceCode(flowCtx)
Defensive patterns
Strategy: validation
Validate before calling
if ctx == nil || ctx.Err() != nil {
return errors.New("device flow context already dead; pass a fresh context")
}
dc, err := c.RequestDeviceCode(ctx) Try / catch
dc, err := c.RequestDeviceCode(ctx)
if err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
// rebuild context; device flow needs minutes, not seconds
}
} Prevention
- Size device-flow context timeouts for human approval time (minutes).
- Keep the device-flow context independent of HTTP request lifetimes.
When it happens
Trigger: 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.
Common situations: Wrapper scripts with very short auth timeouts canceling before the first POST; SDK integrations reusing a stale context; not seen in normal CLI usage.
Related errors
- kimi: context cancelled: %w
- failed to create token request: %w
- kimi: device code request failed: %w
- kimi: failed to read device code response: %w
- kimi: device code request failed with status %d: %s
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/03cb25f0c3930a2a.
Report an issue: GitHub.