{"record":{"id":"f289eeb787d374ca","repo":"netbirdio/netbird","slug":"failed-reading-access-token-response-body-with-err","errorCode":null,"errorMessage":"failed reading access token response body with error: %v","messagePattern":"failed reading access token response body with error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/internal/auth/device_flow.go","lineNumber":233,"sourceCode":"\t\treturn TokenRequestResponse{}, fmt.Errorf(\"failed to create request access token: %v\", err)\n\t}\n\treq.Header.Add(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\tres, err := d.HTTPClient.Do(req)\n\tif err != nil {\n\t\treturn TokenRequestResponse{}, fmt.Errorf(\"failed to request access token with error: %v\", err)\n\t}\n\n\tdefer func() {\n\t\terr := res.Body.Close()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}()\n\n\tbody, err := io.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn TokenRequestResponse{}, fmt.Errorf(\"failed reading access token response body with error: %v\", err)\n\t}\n\n\tif res.StatusCode > 499 {\n\t\treturn TokenRequestResponse{}, fmt.Errorf(\"access token response returned code: %s\", string(body))\n\t}\n\n\ttokenResponse := TokenRequestResponse{}\n\terr = json.Unmarshal(body, &tokenResponse)\n\tif err != nil {\n\t\treturn TokenRequestResponse{}, fmt.Errorf(\"parsing token response failed with error: %v\", err)\n\t}\n\n\treturn tokenResponse, nil\n}\n\n// WaitToken waits user's login and authorize the app. Once the user's authorize\n// it retrieves the access token from Hosted's endpoint and validates it before returning.\n// The method creates a timeout context internally based on info.ExpiresIn.","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/internal/auth/device_flow.go#L215-L251","documentation":"Raised by DeviceAuthorizationFlow.requestToken when io.ReadAll fails while streaming the response body from the IdP token endpoint (client/internal/auth/device_flow.go:231-233). The HTTP request itself succeeded (headers received via d.HTTPClient.Do, a client with a 10s timeout), but the connection broke or timed out mid-body. This is a transport-level read failure, not an OAuth protocol error.","triggerScenarios":"POST to providerConfig.TokenEndpoint (grant_type urn:ietf:params:oauth:grant-type:device_code) succeeds at the TCP/TLS level, then the body read fails: connection reset by the IdP or an intermediate proxy, response body larger/slower than the http.Client 10s Timeout, or a TLS-inspecting middlebox truncating the response.","commonSituations":"Corporate proxies or SSL-inspection appliances cutting long responses, IdP load balancers dropping connections, flaky Wi-Fi/VPN on the user machine, or a slow IdP that exceeds the hard-coded 10-second client timeout while streaming the token payload.","solutions":["Retry the login (netbird up) - transient connection resets resolve themselves on a fresh flow","Check network stability between the client and the IdP token endpoint (curl -v the TokenEndpoint URL)","If behind a proxy or TLS inspection appliance, bypass the IdP domain or install the inspection root CA on the host","If the IdP is consistently slow, the 10s http.Client timeout in NewDeviceAuthorizationFlow may need raising (requires a client rebuild)"],"exampleFix":"// before (device_flow.go NewDeviceAuthorizationFlow)\nhttpClient := &http.Client{\n\tTimeout:   10 * time.Second,\n\tTransport: httpTransport,\n}\n\n// after - tolerate slow IdPs while still bounding the request\nhttpClient := &http.Client{\n\tTimeout:   30 * time.Second,\n\tTransport: httpTransport,\n}","handlingStrategy":"retry","validationCode":"// Pre-flight the token endpoint before starting a device flow\nfunc tokenEndpointReachable(endpoint string) error {\n\treq, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(\"\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\tclient := &http.Client{Timeout: 10 * time.Second}\n\tres, err := client.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"token endpoint unreachable: %w\", err)\n\t}\n\tdefer res.Body.Close()\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"flow, err := oauthFlow.WaitToken(ctx, info)\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed reading access token response body\") {\n\t\t// transport-level read failure: safe to restart the whole flow\n\t\tlog.Warnf(\"token body read failed, retrying login: %v\", err)\n\t\treturn retryLogin(ctx)\n\t}\n\treturn err\n}","preventionTips":["Keep the network path between client and IdP free of truncating proxies and TLS-inspection middleboxes","Pre-flight the token endpoint with a cheap POST before launching the interactive flow","Surface the wrapped %v cause - it distinguishes timeouts from connection resets"],"tags":["oauth2","device-flow","network","idp","timeout"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}