{"record":{"id":"79ed9710733e7ba1","repo":"ginuerzh/gost","slug":"failed-to-read-the-response-body-s","errorCode":null,"errorMessage":"failed to read the response body: %s","messagePattern":"failed to read the response body: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"resolver.go","lineNumber":919,"sourceCode":"\tclient := ex.client\n\tif client == nil {\n\t\tclient = http.DefaultClient\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to perform an HTTPS request: %s\", err)\n\t}\n\n\t// Check response status code\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"returned status code %d\", resp.StatusCode)\n\t}\n\n\t// Read wireformat response from the body\n\tbuf, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read the response body: %s\", err)\n\t}\n\n\treturn buf, nil\n}\n","sourceCodeStart":901,"sourceCodeEnd":924,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/resolver.go#L901-L924","documentation":"The DoH server returned 200 but reading the response body with io.ReadAll failed (resolver.go:919). The 200-status wire-format payload could not be fully received — typically the connection was cut or timed out mid-body, so the DNS response bytes are unavailable.","triggerScenarios":"Exchange() on a dohExchanger where the server closes the connection before sending the complete body, the http.Client Timeout fires while reading the body (timeout covers the entire exchange including body read), the context is cancelled mid-read, or a proxy/TLB truncates the response.","commonSituations":"Flaky mobile/satellite networks dropping connections mid-response; DoH server or load balancer with aggressive idle/read timeouts; http.Client timeout too short for large responses or slow links; intermediaries (corporate proxies) killing long-lived connections.","solutions":["Increase the ExchangerOption timeout — the http.Client Timeout covers body reading too, so a too-short value surfaces here","Retry the Exchange() call with backoff — transient connection resets are common on unstable networks","Check for context cancellation and give the exchange a longer/deeper deadline","Test the endpoint directly (curl the DoH URL) to see if the server/proxy truncates responses","Bypass or reconfigure intermediaries (proxies, VPNs) that cut connections"],"exampleFix":"// before\nexchanger := NewDoHExchanger(endpoint, nil) // default timeout, flaky link\nbuf, err := exchanger.Exchange(ctx, query) // failed to read the response body: ...unexpected EOF\n// after\nexchanger := NewDoHExchanger(endpoint, nil, WithTimeout(15*time.Second))\nfor i := 0; i < 3; i++ { // retry transient body-read failures\n    buf, err = exchanger.Exchange(ctx, query)\n    if err == nil { break }\n    time.Sleep(time.Duration(1<<i) * 100 * time.Millisecond)\n}","handlingStrategy":"retry","validationCode":"if timeout <= 0 || timeout > 30*time.Second {\n    // body reads are covered by the client Timeout; pick a safe value\n    timeout = 15 * time.Second\n}","typeGuard":"func isBodyReadFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"failed to read the response body:\")\n}","tryCatchPattern":"var buf []byte\nvar err error\nfor attempt := 0; attempt < 3; attempt++ {\n    buf, err = exchanger.Exchange(ctx, query)\n    if err == nil { break }\n    if isBodyReadFailure(err) {\n        select {\n        case <-time.After(time.Duration(1<<attempt) * 100 * time.Millisecond):\n            continue\n        case <-ctx.Done():\n            return ctx.Err()\n        }\n    }\n    break\n}","preventionTips":["Set the exchanger timeout large enough to cover slow-link body reads","Always retry Exchange on transient IO errors — DNS queries are idempotent","Respect context cancellation in retry loops","Avoid routing DoH through unreliable intermediaries/proxies","Watch server-side (or LB) read-timeout settings against your client timeout"],"tags":["network","dns","https","io","doh"],"backgroundTag":"response-body-read-failed","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}