hyperledger/fabric · error

faulty node, received: %v

Error message

faulty node, received: %v

What it means

extractBlockFromResponse in the cluster BlockPuller returns this when an ordering node's Deliver response is neither a block nor a recognized error status — the response status is something other than SUCCESS, FORBIDDEN, or SERVICE_UNAVAILABLE. It signals the node misbehaved or the channel/TLS state is broken, and the puller will treat the endpoint as faulty and fail over to another one.

Source

Thrown at orderer/common/cluster/deliver.go:478

		}
		if block.Data == nil {
			return nil, errors.New("block data is nil")
		}
		if block.Header == nil {
			return nil, errors.New("block header is nil")
		}
		if block.Metadata == nil || len(block.Metadata.Metadata) == 0 {
			return nil, errors.New("block metadata is empty")
		}
		return block, nil
	case *orderer.DeliverResponse_Status:
		if t.Status == common.Status_FORBIDDEN {
			return nil, ErrForbidden
		}
		if t.Status == common.Status_SERVICE_UNAVAILABLE {
			return nil, ErrServiceUnavailable
		}
		return nil, errors.Errorf("faulty node, received: %v", resp)
	default:
		return nil, errors.Errorf("response is of type %v, but expected a block", reflect.TypeOf(resp.Type))
	}
}

func (p *BlockPuller) seekLastEnvelope() (*common.Envelope, error) {
	return protoutil.CreateSignedEnvelopeWithTLSBinding(
		common.HeaderType_DELIVER_SEEK_INFO,
		p.Channel,
		p.Signer,
		last(),
		int32(0),
		uint64(0),
		util.ComputeSHA256(p.TLSCert),
	)
}

func (p *BlockPuller) seekNextEnvelope(startSeq uint64) (*common.Envelope, error) {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify all ordering nodes run compatible Fabric versions and share the channel configuration
  2. Check the remote node's logs for why the deliver request was rejected (status logged in the response)
  3. Confirm mutual TLS certificates and TLSRootCAs are correctly configured for the cluster connection
  4. Ensure the pulling node is actually a member of the channel with a valid identity
Defensive patterns

Strategy: retry

Validate before calling

if resp.GetType() != orderer.DeliverResponse_BLOCK { return fmt.Errorf("non-block response type: %v", resp.Type) }

Type guard

func isBlockResponse(resp *orderer.DeliverResponse) bool { return resp != nil && resp.GetType() == orderer.DeliverResponse_BLOCK }

Try / catch

resp, err := puller.PullBlock(seq)
if err != nil {
    if errors.Is(err, cluster.ErrForbidden) || errors.Is(err, cluster.ErrServiceUnavailable) {
        // fail over / retry another endpoint
    }
    return err
}

Prevention

When it happens

Trigger: A DeliverResponse arrives with a Status other than common.Status_SUCCESS, Status_FORBIDDEN, or Status_SERVICE_UNAVAILABLE (e.g. BAD_REQUEST from an incompatible SeekInfo, or a node rejecting the seek); any non-DeliverResponse shape reaching the extractor.

Common situations: Fabric version mismatch between the pulling orderer and the remote ordering node; a consenter removed from the channel still listed in the cluster configuration; misconfigured mutual TLS causing the remote node to reject the deliver seek; pointing the puller at a non-orderer gRPC endpoint.

Related errors


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