hyperledger/fabric · error

error reading response body

Error message

error reading response body

What it means

Returned when io.ReadAll(resp.Body) fails while consuming the HTTP response from a CouchDB range query. The library received an HTTP response but could not read the body stream off the wire (connection dropped mid-response, timeout, or transport reset). The raw io error is wrapped with this fixed message.

Source

Thrown at core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdb.go:890

	resp, _, err := dbclient.handleRequest(http.MethodGet, "RangeDocRange", rangeURL, nil, "", "", maxRetries, true, &queryParms, "_all_docs")
	if err != nil {
		return nil, "", err
	}
	defer closeResponseBody(resp)

	if couchdbLogger.IsEnabledFor(zapcore.DebugLevel) {
		dump, err2 := httputil.DumpResponse(resp, false)
		if err2 != nil {
			log.Fatal(err2)
		}
		// compact debug log by replacing carriage return / line feed with dashes to separate http headers
		couchdbLogger.Debugf("[%s] HTTP Response: %s", dbclient.dbName, bytes.Replace(dump, []byte{0x0d, 0x0a}, []byte{0x20, 0x7c, 0x20}, -1))
	}

	// handle as JSON document
	jsonResponseRaw, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, "", errors.Wrap(err, "error reading response body")
	}

	jsonResponse := &rangeQueryResponse{}
	err2 := json.Unmarshal(jsonResponseRaw, &jsonResponse)
	if err2 != nil {
		return nil, "", errors.Wrap(err2, "error unmarshalling json data")
	}

	// if an additional record is found, then reduce the count by 1
	// and populate the nextStartKey
	if jsonResponse.TotalRows > limit {
		jsonResponse.TotalRows = limit
	}

	couchdbLogger.Debugf("[%s] Total Rows: %d", dbclient.dbName, jsonResponse.TotalRows)

	// Use the next endKey as the starting default for the nextStartKey
	nextStartKey := endKey

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Retry the range query; the error is usually transient network/transport failure.
  2. Check CouchDB server health/logs around the failure time for crashes or restarts.
  3. Reduce result-set size by narrowing the startKey/endKey or lowering limit to shorten the response window.
  4. Inspect network path (proxies, LB idle timeouts) between peer and CouchDB and raise timeout limits.
Defensive patterns

Strategy: retry

Validate before calling

if err := couchHealthCheck(client); err != nil {
    return fmt.Errorf("couchdb unreachable before range scan: %w", err)
}

Try / catch

results, err := db.RangeScan(startKey, endKey)
if err != nil && strings.Contains(err.Error(), "error reading response body") {
    results, err = retryWithBackoff(3, func() ([]*queryResult, string, error) {
        return db.RangeScan(startKey, endKey)
    })
}

Prevention

When it happens

Trigger: During handleRangeQuery: the _all_docs (or _design/...) GET returns headers successfully, then the TCP connection breaks or times out while streaming the JSON body.

Common situations: CouchDB container restarted or OOM-killed mid-request, load balancer idle-timeout closing long responses, network flakiness between peer and CouchDB, or very large range scans over slow links.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/d97f844f02d78469. Report an issue: GitHub.