{"record":{"id":"bdeab8e09a1ad937","repo":"sipeed/picoclaw","slug":"reading-device-code-response-w","errorCode":null,"errorMessage":"reading device code response: %w","messagePattern":"reading device code response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/oauth.go","lineNumber":268,"sourceCode":"// Returns the info needed for the user to authenticate in a browser.\nfunc RequestDeviceCode(cfg OAuthProviderConfig) (*DeviceCodeInfo, error) {\n\treqBody, _ := json.Marshal(map[string]string{\n\t\t\"client_id\": cfg.ClientID,\n\t})\n\n\tresp, err := http.Post(\n\t\tcfg.Issuer+\"/api/accounts/deviceauth/usercode\",\n\t\t\"application/json\",\n\t\tstrings.NewReader(string(reqBody)),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"requesting device code: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading device code response: %w\", err)\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"device code request failed: %s\", string(body))\n\t}\n\n\tdeviceResp, err := parseDeviceCodeResponse(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing device code response: %w\", err)\n\t}\n\n\tif deviceResp.Interval < 1 {\n\t\tdeviceResp.Interval = 5\n\t}\n\n\treturn &DeviceCodeInfo{\n\t\tDeviceAuthID: deviceResp.DeviceAuthID,\n\t\tUserCode:     deviceResp.UserCode,\n\t\tVerifyURL:    cfg.Issuer + \"/codex/device\",","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/auth/oauth.go#L250-L286","documentation":"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.","triggerScenarios":"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.","commonSituations":"Unstable networks; aggressive proxy body limits; provider-side connection pool recycling mid-response.","solutions":["Retry RequestDeviceCode once or twice with a short backoff — transient body breaks dominate","curl the same endpoint to confirm the body transfers cleanly outside the app","Bypass or reconfigure intercepting proxies for the issuer host","If persistent, capture with the wrapped error's errno/context and report upstream"],"exampleFix":"// before: one-shot device code request\ninfo, err := auth.RequestDeviceCode(cfg)\n\n// after: bounded retry on transport failure\nvar info *auth.DeviceCodeInfo\nerr := retryN(3, time.Second, func() error {\n    i, e := auth.RequestDeviceCode(cfg)\n    if i != nil { info = i }\n    return e\n})","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := retryN(3, 500*time.Millisecond, func() error {\n    info, e := auth.RequestDeviceCode(cfg)\n    if e != nil && strings.Contains(e.Error(), \"reading device code response\") {\n        return e // mid-body truncation: retry\n    }\n    if info != nil { deviceInfo = info }\n    return retryStop{e}\n})","preventionTips":["Retry body-read failures of the device-code endpoint a bounded number of times","Confirm clean transfers with curl when retries keep failing","Avoid intercepting proxies on the issuer host"],"tags":["network","http","device-flow","retry"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}