{"record":{"id":"a1bfdf6cf494d1b0","repo":"hyperledger/fabric","slug":"first-message-needs-to-be-a-register","errorCode":null,"errorMessage":"First message needs to be a register","messagePattern":"First message needs to be a register","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/accesscontrol/access.go","lineNumber":63,"sourceCode":"\n// Generate returns a pair of certificate and private key,\n// and associates the hash of the certificate with the given\n// chaincode name\nfunc (ac *Authenticator) Generate(ccName string) (*CertAndPrivKeyPair, error) {\n\tcert, err := ac.mapper.genCert(ccName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &CertAndPrivKeyPair{\n\t\tKey:  cert.Key,\n\t\tCert: cert.Cert,\n\t}, nil\n}\n\nfunc (ac *Authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error {\n\tif msg.Type != pb.ChaincodeMessage_REGISTER {\n\t\tlogger.Warning(\"Got message\", msg, \"but expected a ChaincodeMessage_REGISTER message\")\n\t\treturn errors.New(\"First message needs to be a register\")\n\t}\n\n\tchaincodeID := &pb.ChaincodeID{}\n\terr := proto.Unmarshal(msg.Payload, chaincodeID)\n\tif err != nil {\n\t\tlogger.Warning(\"Failed unmarshalling message:\", err)\n\t\treturn err\n\t}\n\tccName := chaincodeID.Name\n\t// Obtain certificate from stream\n\thash := extractCertificateHashFromContext(stream.Context())\n\tif len(hash) == 0 {\n\t\terrMsg := fmt.Sprintf(\"TLS is active but chaincode %s didn't send certificate\", ccName)\n\t\tlogger.Warning(errMsg)\n\t\treturn errors.New(errMsg)\n\t}\n\t// Look it up in the mapper\n\tregisteredName := ac.mapper.lookup(certHash(hash))","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/accesscontrol/access.go#L45-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: sending a transaction before registration\nstream.Send(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION, ...})\n// after: register first\npayload, _ := proto.Marshal(&pb.ChaincodeID{Name: ccName})\nstream.Send(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload})","handlingStrategy":"validation","validationCode":"// shim-side: assert first outbound message is REGISTER\nif firstMsg.Type != pb.ChaincodeMessage_REGISTER {\n    return errors.New(\"client bug: first chaincode message must be REGISTER\")\n}","typeGuard":"func isFirstMessageRegister(msg *pb.ChaincodeMessage) bool {\n    return msg != nil && msg.Type == pb.ChaincodeMessage_REGISTER\n}","tryCatchPattern":"if err := authenticator.authenticate(msg, stream); err != nil {\n    if strings.Contains(err.Error(), \"First message needs to be a register\") {\n        // recreate the stream and send REGISTER first\n    }\n}","preventionTips":["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"],"tags":["hyperledger-fabric","chaincode","grpc","access-control","protocol"],"backgroundTag":"missing-register-message","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}