{"record":{"id":"be2563d396aa17c4","repo":"hyperledger/fabric","slug":"invalid-version-in-channelheader-expected-0-got","errorCode":null,"errorMessage":"invalid version in ChannelHeader. Expected 0, got [%d]","messagePattern":"invalid version in ChannelHeader\\. Expected 0, got \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tx/endorser/parser.go","lineNumber":133,"sourceCode":"\t\tResponse:     ccAction.Response,\n\t\tEvents:       ccAction.Events,\n\t\tResults:      ccAction.Results,\n\t\tEndorsements: ccActionPayload.Action.Endorsements,\n\t\tChaincodeID:  hdrExt.ChaincodeId,\n\t\tType:         txenv.ChannelHeader.Type,\n\t\tVersion:      txenv.ChannelHeader.Version,\n\t\tEpoch:        txenv.ChannelHeader.Epoch,\n\t\tNonce:        txenv.SignatureHeader.Nonce,\n\t}, nil\n}\n\nfunc (e *EndorserTx) validate() error {\n\tif e.Epoch != 0 {\n\t\treturn errors.Errorf(\"invalid epoch in ChannelHeader. Expected 0, got [%d]\", e.Epoch)\n\t}\n\n\tif e.Version != 0 {\n\t\treturn errors.Errorf(\"invalid version in ChannelHeader. Expected 0, got [%d]\", e.Version)\n\t}\n\n\tif err := ValidateChannelID(e.ChannelID); err != nil {\n\t\treturn err\n\t}\n\n\tif len(e.Nonce) == 0 {\n\t\treturn errors.New(\"empty nonce\")\n\t}\n\n\tif len(e.Creator) == 0 {\n\t\treturn errors.New(\"empty creator\")\n\t}\n\n\tif e.ChaincodeID == nil {\n\t\treturn errors.New(\"nil ChaincodeId\")\n\t}\n","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/tx/endorser/parser.go#L115-L151","documentation":"The parsed ChannelHeader has a non-zero Version field. Fabric endorser transactions use version 0 for the channel header; a non-zero version means the header was constructed incorrectly or by tooling using a different versioning scheme. The parser rejects it to guarantee the transaction matches Fabric's expected format.","triggerScenarios":"UnmarshalEndorserTxAndValidate is given an envelope whose ChannelHeader.Version != 0 — e.g. a header built with Version set manually or reused from another header type (e.g. config updates that use versioning).","commonSituations":"Copying headers from config or block transactions that legitimately set Version; SDK/tooling that defaults Version to 1; version-skew after Fabric upgrades where custom builders picked wrong values.","solutions":["Leave ChannelHeader.Version unset (zero value) when building the transaction header.","Use protoutil.BuildChannelHeader to construct headers instead of manual structs.","Check for header reuse across transaction types and create a fresh header for endorser txs."],"exampleFix":"// before\nch := &common.ChannelHeader{ChannelId: \"mychannel\", Version: 1}\n// after\nch := &common.ChannelHeader{ChannelId: \"mychannel\"} // Version zero value","handlingStrategy":"validation","validationCode":"func hasZeroVersion(ch *common.ChannelHeader) bool {\n    return ch.GetVersion() == 0\n}\n// check header before submission: if !hasZeroVersion(header) { fix header }","typeGuard":"func isVersionZero(header *common.ChannelHeader) bool {\n    return header != nil && header.Version == 0\n}","tryCatchPattern":"tx, err := parser.UnmarshalEndorserTxAndValidate(env)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid version\") {\n        // rebuild the header with version 0 and resubmit\n        return ErrInvalidHeader\n    }\n    return err\n}","preventionTips":["Leave ChannelHeader.Version as the zero value for endorser transactions.","Construct headers via protoutil.BuildChannelHeader.","Review custom header builders after Fabric version upgrades."],"tags":["hyperledger-fabric","channel-header","validation"],"backgroundTag":"invalid-channel-header","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"}