hyperledger/fabric · error

got unexpected status: %v -- %s

Error message

got unexpected status: %v -- %s

What it means

getAck reads the broadcast stream response from the orderer; if the returned status is anything other than SUCCESS, it raises this error carrying the cb.Status enum and the orderer-provided info string. It means the orderer explicitly rejected the submitted envelope rather than a transport failure.

Source

Thrown at internal/peer/common/broadcastclient.go:44

	oc, err := NewOrdererClientFromEnv()
	if err != nil {
		return nil, err
	}
	bc, err := oc.Broadcast()
	if err != nil {
		return nil, err
	}

	return &BroadcastGRPCClient{Client: bc}, nil
}

func (s *BroadcastGRPCClient) getAck() error {
	msg, err := s.Client.Recv()
	if err != nil {
		return err
	}
	if msg.Status != cb.Status_SUCCESS {
		return errors.Errorf("got unexpected status: %v -- %s", msg.Status, msg.Info)
	}
	return nil
}

// Send data to orderer
func (s *BroadcastGRPCClient) Send(env *cb.Envelope) error {
	if err := s.Client.Send(env); err != nil {
		return errors.WithMessage(err, "could not send to orderer node")
	}

	err := s.getAck()

	return err
}

func (s *BroadcastGRPCClient) Close() error {
	return s.Client.CloseSend()
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Read the msg.Info text after the '--' for the orderer's specific rejection reason
  2. Check orderer logs (e.g. raft leader availability, channel existence) for the matching error
  3. If SERVICE_UNAVAILABLE, wait for/order the raft leader election to complete and retry
  4. If FORBIDDEN, fix the client's MSP/certificates so it has write access to the channel
  5. If BAD_REQUEST on channel update, re-validate the config update envelope against current config

Example fix

// before
err = broadcastClient.Send(env) // got unexpected status: SERVICE_UNAVAILABLE -- no leader
// after
// check orderer raft status first, then retry
if status == cb.Status_SERVICE_UNAVAILABLE { time.Sleep(2 * time.Second); err = broadcastClient.Send(env) }
Defensive patterns

Strategy: retry

Validate before calling

// verify channel exists and client can write before sending
resp, err := cf.ChannelClient.GetChannelInfo()
if err != nil { return fmt.Errorf("channel %s not reachable: %w", channelID, err) }

Type guard

func isOrdererStatusError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "got unexpected status:")
}

Try / catch

if err := broadcastClient.Send(env); err != nil {
    if strings.Contains(err.Error(), "SERVICE_UNAVAILABLE") {
        return retryWithBackoff(func() error { return broadcastClient.Send(env) })
    }
    log.Errorf("orderer rejected envelope: %v", err) // inspect status + info after '--'
    return err
}

Prevention

When it happens

Trigger: Submitting a transaction/config envelope via BroadcastGRPCClient.Send and the orderer replies with a non-SUCCESS status such as BAD_REQUEST, FORBIDDEN, SERVICE_UNAVAILABLE, or NOT_READY, with msg.Info describing the cause.

Common situations: Orderer cluster has no leader (SERVICE_UNAVAILABLE); channel does not exist (BAD_REQUEST); the submitting client lacks write permission (FORBIDDEN); config update validation failure during channel update; submitting to wrong channel's orderer.

Related errors


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