{"record":{"id":"b9ea8285fb838e91","repo":"hyperledger/fabric","slug":"could-not-unmarshal-signature-policy-envelope","errorCode":null,"errorMessage":"could not unmarshal signature policy envelope","messagePattern":"could not unmarshal signature policy envelope","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/handlers/validation/builtin/v20/validation_logic.go","lineNumber":58,"sourceCode":"}\n\n//go:generate mockery -dir . -name StateBasedValidator -case underscore -output mocks/\n\n// toApplicationPolicyTranslator implements statebased.PolicyTranslator\n// by translating SignaturePolicyEnvelope policies into ApplicationPolicy\n// ones; this is required because the 2.0 validator is supplied with a\n// policy evaluator that can only understand ApplicationPolicy policies.\ntype toApplicationPolicyTranslator struct{}\n\nfunc (n *toApplicationPolicyTranslator) Translate(b []byte) ([]byte, error) {\n\tif len(b) == 0 {\n\t\treturn b, nil\n\t}\n\n\tspe := &common.SignaturePolicyEnvelope{}\n\terr := proto.Unmarshal(b, spe)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"could not unmarshal signature policy envelope\")\n\t}\n\n\treturn protoutil.MarshalOrPanic(&peer.ApplicationPolicy{\n\t\tType: &peer.ApplicationPolicy_SignaturePolicy{\n\t\t\tSignaturePolicy: spe,\n\t\t},\n\t}), nil\n}\n\n// New creates a new instance of the default VSCC\n// Typically this will only be invoked once per peer\nfunc New(c vc.Capabilities, s vs.StateFetcher, d vi.IdentityDeserializer, pe vp.PolicyEvaluator, cor statebased.CollectionResources) *Validator {\n\tvpmgr := &statebased.KeyLevelValidationParameterManagerImpl{\n\t\tStateFetcher:     s,\n\t\tPolicyTranslator: &toApplicationPolicyTranslator{},\n\t}\n\teval := statebased.NewV20Evaluator(vpmgr, pe, cor, s)\n\tsbv := statebased.NewKeyLevelValidator(eval, vpmgr)","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/handlers/validation/builtin/v20/validation_logic.go#L40-L76","documentation":"This error wraps a protobuf unmarshal failure while decoding bytes into a common.SignaturePolicyEnvelope in the v2.0 application-policy translator. It is thrown because the input bytes are not a valid serialized SignaturePolicyEnvelope, so the translator cannot produce a peer.ApplicationPolicy.","triggerScenarios":"Translate() is called with bytes that are not a valid proto-encoded SignaturePolicyEnvelope — e.g. bytes produced by a different policy type (ImplicitMetaPolicy), corrupted policy bytes, or a policy marshaled by an incompatible proto schema.","commonSituations":"Channel config referencing an application policy whose stored value is an ImplicitMetaPolicy rather than a signature policy; fabric peers consuming configs generated by mismatched fabric versions; corrupted channel artifacts in genesis blocks or config update transactions.","solutions":["Verify the policy being translated is actually a SignaturePolicyEnvelope (check the config policy type in the channel configuration)","Regenerate the channel config/genesis block with a consistent fabric version (configtxlator can help inspect the policy)","Decode the bytes with configtxlator to confirm the policy structure and schema version","If writing tests (as TestToApplicationPolicyTranslator_Translate does), construct the envelope with protoutil/proto.Marshal of a valid &common.SignaturePolicyEnvelope"],"exampleFix":"// before\nb := proto.Marshal(implicitMetaPolicy) // wrong type\npol, err := translator.Translate(b)\n// after\nspe := &common.SignaturePolicyEnvelope{Version: 0, Rule: cauthdsl.SignedBy(0), Identities: ids}\nb := protoutil.MarshalOrPanic(spe)\npol, err := translator.Translate(b)","handlingStrategy":"validation","validationCode":"import \"google.golang.org/protobuf/proto\"\nfunc isSignaturePolicyEnvelope(b []byte) bool {\n    spe := &common.SignaturePolicyEnvelope{}\n    return proto.Unmarshal(b, spe) == nil && spe.Identities != nil\n}","typeGuard":"func isSignaturePolicyEnvelope(b []byte) bool {\n    spe := &common.SignaturePolicyEnvelope{}\n    return proto.Unmarshal(b, spe) == nil\n}","tryCatchPattern":"spe, err := translate(b)\nif err != nil {\n    if strings.Contains(err.Error(), \"could not unmarshal signature policy envelope\") {\n        // log policy bytes, treat as invalid/unsupported policy config\n    }\n    return err\n}","preventionTips":["Confirm the policy type in channel config before translating (ImplicitMeta vs Signature)","Use configtxlator to inspect policy bytes","Pin matching fabric-protos versions across producer and consumer","Always construct envelopes with proto.Marshal, not hand-rolled bytes"],"tags":["protobuf","policy","unmarshal","fabric"],"backgroundTag":"protobuf-unmarshal-failed","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"}