sipeed/picoclaw · error

reading device code response: %w

Error message

reading device code response: %w

What it means

io.ReadAll(resp.Body) failed while streaming the device-code response body (oauth.go:268). The POST got headers back, but the body read broke — connection reset mid-body, or the default http.Client's response-header timeout variant cutting a slow trickle. The status code is never inspected on this path.

Source

Thrown at pkg/auth/oauth.go:268

// Returns the info needed for the user to authenticate in a browser.
func RequestDeviceCode(cfg OAuthProviderConfig) (*DeviceCodeInfo, error) {
	reqBody, _ := json.Marshal(map[string]string{
		"client_id": cfg.ClientID,
	})

	resp, err := http.Post(
		cfg.Issuer+"/api/accounts/deviceauth/usercode",
		"application/json",
		strings.NewReader(string(reqBody)),
	)
	if err != nil {
		return nil, fmt.Errorf("requesting device code: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("reading device code response: %w", err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("device code request failed: %s", string(body))
	}

	deviceResp, err := parseDeviceCodeResponse(body)
	if err != nil {
		return nil, fmt.Errorf("parsing device code response: %w", err)
	}

	if deviceResp.Interval < 1 {
		deviceResp.Interval = 5
	}

	return &DeviceCodeInfo{
		DeviceAuthID: deviceResp.DeviceAuthID,
		UserCode:     deviceResp.UserCode,
		VerifyURL:    cfg.Issuer + "/codex/device",

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Retry RequestDeviceCode once or twice with a short backoff — transient body breaks dominate
  2. curl the same endpoint to confirm the body transfers cleanly outside the app
  3. Bypass or reconfigure intercepting proxies for the issuer host
  4. If persistent, capture with the wrapped error's errno/context and report upstream

Example fix

// before: one-shot device code request
info, err := auth.RequestDeviceCode(cfg)

// after: bounded retry on transport failure
var info *auth.DeviceCodeInfo
err := retryN(3, time.Second, func() error {
    i, e := auth.RequestDeviceCode(cfg)
    if i != nil { info = i }
    return e
})
Defensive patterns

Strategy: retry

Try / catch

err := retryN(3, 500*time.Millisecond, func() error {
    info, e := auth.RequestDeviceCode(cfg)
    if e != nil && strings.Contains(e.Error(), "reading device code response") {
        return e // mid-body truncation: retry
    }
    if info != nil { deviceInfo = info }
    return retryStop{e}
})

Prevention

When it happens

Trigger: Server accepts the request then drops the connection during the body; an intermediary proxy flushing headers but truncating the body; flaky mobile/Wi-Fi links; server closing keep-alive prematurely.

Common situations: Unstable networks; aggressive proxy body limits; provider-side connection pool recycling mid-response.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/bdeab8e09a1ad937. Report an issue: GitHub.