router-for-me/CLIProxyAPI · error

kimi: failed to read device code response: %w

Error message

kimi: failed to read device code response: %w

What it means

The HTTP POST to Kimi's device authorization endpoint (https://auth.kimi.com/api/oauth/device_authorization) succeeded at the transport level, but reading the response body with io.ReadAll failed. This means the connection was interrupted between receiving response headers and receiving the full body. The device code was never obtained, so the device flow cannot proceed.

Source

Thrown at internal/auth/kimi/kimi.go:207

	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)
	if err != nil {
		return nil, fmt.Errorf("kimi: failed to read device code response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("kimi: device code request failed with status %d: %s", resp.StatusCode, string(bodyBytes))
	}

	var deviceCode DeviceCodeResponse
	if err = json.Unmarshal(bodyBytes, &deviceCode); err != nil {
		return nil, fmt.Errorf("kimi: failed to parse device code response: %w", err)
	}

	return &deviceCode, nil
}

// PollForToken polls the token endpoint until the user authorizes or the device code expires.
func (c *DeviceFlowClient) PollForToken(ctx context.Context, deviceCode *DeviceCodeResponse) (*KimiTokenData, error) {
	if deviceCode == nil {
		return nil, fmt.Errorf("kimi: device code is nil")

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Retry StartDeviceFlow once — this is a transient transport failure and a new request gets a fresh connection
  2. Check whether an HTTP(S) proxy (HTTP_PROXY/HTTPS_PROXY env vars) is interfering and bypass or configure it for auth.kimi.com
  3. Verify basic connectivity: curl -i -X POST https://auth.kimi.com/api/oauth/device_authorization and confirm the body arrives fully
  4. If it persists, inspect httpClient timeout configuration in NewDeviceFlowClient — a very short client timeout can abort mid-body reads

Example fix

// before
deviceCode, err := k.StartDeviceFlow(ctx)
if err != nil {
    return err // fails outright on transient body read error
}

// after
deviceCode, err := k.StartDeviceFlow(ctx)
if err != nil {
    if isTransientNetErr(err) { // net.Error, io.ErrUnexpectedEOF, connection reset
        time.Sleep(2 * time.Second)
        deviceCode, err = k.StartDeviceFlow(ctx)
    }
    if err != nil {
        return err
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// Verify the auth host is reachable and proxy env is sane before starting the flow
if _, err := net.LookupHost("auth.kimi.com"); err != nil {
    return fmt.Errorf("cannot resolve auth.kimi.com: %w", err)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to read device code response") {
    time.Sleep(2 * time.Second)
    deviceCode, err = k.StartDeviceFlow(ctx)
}

Prevention

When it happens

Trigger: Connection reset or TLS renegotiation mid-body while auth.kimi.com streams the device code JSON; an intercepting proxy that closes the stream early; response with Content-Length larger than what the server actually sends; very slow network causing the client reader to abort.

Common situations: Corporate proxies/MITM proxies truncating responses, flaky mobile or containerized networks, transient Moonshot-side connection resets, running in CI with restricted egress that allows headers but drops body.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/9758a24a4ef82392. Report an issue: GitHub.