hyperledger/fabric · error

error unmarshalling json data

Error message

error unmarshalling json data

What it means

Returned when json.Unmarshal fails to decode the raw response body into the rangeQueryResponse struct during a CouchDB range query. It means the server responded with bytes that are not the expected JSON shape — typically an HTML/empty/proxy error body instead of CouchDB's {total_rows, offset, rows} JSON.

Source

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

	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

	for index, row := range jsonResponse.Rows {

		docMetadata := &docMetadata{}
		err3 := json.Unmarshal(row.Doc, &docMetadata)
		if err3 != nil {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Log/inspect the response body (peer debug logging dumps it) to see what was actually returned.
  2. Verify the configured address really points to CouchDB (curl the /_all_docs endpoint manually).
  3. Check proxy/load-balancer error pages and increase proxy timeouts so real JSON is returned.
  4. Retry after confirming CouchDB is healthy; check couchdb logs for 5xx responses.
Defensive patterns

Strategy: try-catch

Validate before calling

resp, err := http.Get(couchURL + "/_all_docs?limit=1")
if err == nil && !isJSONContentType(resp.Header.Get("Content-Type")) {
    return errors.New("endpoint did not return JSON; check proxy/port")
}

Type guard

func isCouchDBJSON(body []byte) bool {
    var probe map[string]json.RawMessage
    return json.Unmarshal(body, &probe) == nil && probe["rows"] != nil
}

Try / catch

results, err := db.RangeScan(startKey, endKey)
var parseErr *ParseError
if errors.As(err, &parseErr) || strings.Contains(err.Error(), "error unmarshalling json data") {
    log.Printf("non-JSON CouchDB response; dumping endpoint health and proxy logs")
}

Prevention

When it happens

Trigger: handleRangeQuery GET succeeds at HTTP level but the body is not valid JSON: CouchDB returned an error page, an empty body from an interrupted proxy, or a non-CouchDB service answered on the port.

Common situations: Reverse proxy (nginx/HAProxy) returning HTML 502/504 pages, something else listening on port 5984, TLS proxy mangling responses, or CouchDB returning truncated bodies under memory pressure.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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