hyperledger/fabric · error

marshal failed: proto: Marshal called with nil

Error message

marshal failed: proto: Marshal called with nil

What it means

In the query-response path, after collecting the query result, the handler sanity-checks that the payload to return is non-nil before proto.Marshal. If getQueryResponseForIterator yields a nil payload, the peer returns an error literally 'marshal failed: proto: Marshal called with nil' and cleans up the query context. It guards against marshalling a nil protobuf message which would otherwise panic or produce a broken response.

Source

Thrown at core/chaincode/handler.go:877

		}
		rangeIter, err = txContext.TXSimulator.GetStateRangeScanIteratorWithPagination(namespaceID,
			startKey, getStateByRange.EndKey, metadata.PageSize)
	} else {
		rangeIter, err = txContext.TXSimulator.GetStateRangeScanIterator(namespaceID, getStateByRange.StartKey, getStateByRange.EndKey)
	}
	if err != nil {
		return nil, errors.WithStack(err)
	}
	txContext.InitializeQueryContext(iterID, rangeIter)

	payload, err := h.QueryResponseBuilder.BuildQueryResponse(txContext, rangeIter, iterID, isPaginated, totalReturnLimit)
	if err != nil {
		txContext.CleanupQueryContext(iterID)
		return nil, errors.WithStack(err)
	}
	if payload == nil {
		txContext.CleanupQueryContext(iterID)
		return nil, errors.New("marshal failed: proto: Marshal called with nil")
	}

	payloadBytes, err := proto.Marshal(payload)
	if err != nil {
		txContext.CleanupQueryContext(iterID)
		return nil, errors.Wrap(err, "marshal failed")
	}

	chaincodeLogger.Debugf("Got keys and values. Sending %s", pb.ChaincodeMessage_RESPONSE)
	return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: payloadBytes, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
}

// Handles query to ledger for query state next
func (h *Handler) HandleQueryStateNext(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
	queryStateNext := &pb.QueryStateNext{}
	err := proto.Unmarshal(msg.Payload, queryStateNext)
	if err != nil {
		return nil, errors.Wrap(err, "unmarshal failed")

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Upgrade Hyperledger Fabric to the latest patch release; this guard indicates an unexpected nil that upstream fixes have addressed.
  2. Retry the range/query transaction; transient query-context issues may resolve.
  3. Check for query-context expiry (totalQueryLimit / query timeout) and reduce result window size or use pagination.
  4. Inspect peer logs around the query for the underlying ledger error that produced a nil payload.
Defensive patterns

Strategy: retry

Type guard

func hasValidQueryPayload(payload interface{ Reset(); String() string; ProtoMessage() }) bool { return payload != nil && !reflect.ValueOf(payload).IsNil() }

Try / catch

iter, err := stub.GetStateByRange(start, end)
if err != nil && strings.Contains(err.Error(), "marshal failed") {
    // retry transaction once; if persistent, reduce query window / upgrade peer
    return retryRangeQuery(start, end)
}

Prevention

When it happens

Trigger: The internal query-response builder returns a nil protobuf payload for an iterator ID — e.g. the next-state result construction failed to produce a valid QueryResponse message while iterating range/query results.

Common situations: Peer-side iterator/query-context issues (expired or corrupted query context), ledger provider returning empty result structures, or Fabric bugs in specific versions around paginated queries.

Related errors


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