hyperledger/fabric · error
First message needs to be a register
Error message
First message needs to be a register
What it means
The peer's chaincode access control Authenticator requires that the very first chaincode message received on a newly established stream is a ChaincodeMessage_REGISTER. Any other message type on a fresh stream is rejected with this error, because registration establishes the chaincode's identity (name and certificate) for the connection.
Source
Thrown at core/chaincode/accesscontrol/access.go:63
// Generate returns a pair of certificate and private key,
// and associates the hash of the certificate with the given
// chaincode name
func (ac *Authenticator) Generate(ccName string) (*CertAndPrivKeyPair, error) {
cert, err := ac.mapper.genCert(ccName)
if err != nil {
return nil, err
}
return &CertAndPrivKeyPair{
Key: cert.Key,
Cert: cert.Cert,
}, nil
}
func (ac *Authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error {
if msg.Type != pb.ChaincodeMessage_REGISTER {
logger.Warning("Got message", msg, "but expected a ChaincodeMessage_REGISTER message")
return errors.New("First message needs to be a register")
}
chaincodeID := &pb.ChaincodeID{}
err := proto.Unmarshal(msg.Payload, chaincodeID)
if err != nil {
logger.Warning("Failed unmarshalling message:", err)
return err
}
ccName := chaincodeID.Name
// Obtain certificate from stream
hash := extractCertificateHashFromContext(stream.Context())
if len(hash) == 0 {
errMsg := fmt.Sprintf("TLS is active but chaincode %s didn't send certificate", ccName)
logger.Warning(errMsg)
return errors.New(errMsg)
}
// Look it up in the mapper
registeredName := ac.mapper.lookup(certHash(hash))View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the chaincode shim sends ChaincodeMessage_REGISTER as the first message after stream establishment.
- Align the fabric chaincode shim version with the peer's Fabric version (rebuild the chaincode image with a compatible shim).
- Check for reconnect logic that reuses a stream without re-registering — recreate the stream and send REGISTER first.
- If testing manually, send a REGISTER message with a valid ChaincodeID payload before anything else.
Example fix
// before: sending a transaction before registration
stream.Send(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION, ...})
// after: register first
payload, _ := proto.Marshal(&pb.ChaincodeID{Name: ccName})
stream.Send(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload}) Defensive patterns
Strategy: validation
Validate before calling
// shim-side: assert first outbound message is REGISTER
if firstMsg.Type != pb.ChaincodeMessage_REGISTER {
return errors.New("client bug: first chaincode message must be REGISTER")
} Type guard
func isFirstMessageRegister(msg *pb.ChaincodeMessage) bool {
return msg != nil && msg.Type == pb.ChaincodeMessage_REGISTER
} Try / catch
if err := authenticator.authenticate(msg, stream); err != nil {
if strings.Contains(err.Error(), "First message needs to be a register") {
// recreate the stream and send REGISTER first
}
} Prevention
- Use the official fabric-chaincode-go shim rather than a hand-rolled client
- Pin shim and peer Fabric versions to compatible releases
- Ensure retry logic re-creates the gRPC stream and re-registers, never reuses half-open streams
When it happens
Trigger: A chaincode process (or any client) connecting to the peer's chaincode support port and sending a message whose Type is not REGISTER (e.g. TRANSACTION, READY, PUT_STATE) before registering.
Common situations: Custom or old chaincode shims speaking an incompatible protocol version; a networking proxy/retry layer replaying a stream mid-conversation so the peer sees a non-first message first; manually testing the ccstream port with a raw gRPC client; mismatched fabric-chaincode shim and peer versions.
Related errors
- TLS is active but chaincode %s didn't send certificate
- Chaincode %s with given certificate hash %v not found in reg
- Chaincode %s with given certificate hash %v belongs to a dif
- Recv() error: %v, closing connection
- Message is neither a Submit nor Consensus request
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/a1bfdf6cf494d1b0.
Report an issue: GitHub.