{"record":{"id":"e68263ac652280c9","repo":"hyperledger/fabric","slug":"signed-chaincode-deployment-spec-cannot-be-nil-in","errorCode":null,"errorMessage":"signed chaincode deployment spec cannot be nil in a package","messagePattern":"signed chaincode deployment spec cannot be nil in a package","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/common/ccprovider/sigcdspackage.go","lineNumber":188,"sourceCode":"\t// compute the id\n\thash.Write(scdsdata.CodeHash)\n\thash.Write(scdsdata.MetaDataHash)\n\thash.Write(scdsdata.SignatureHash)\n\n\tid := hash.Sum(nil)\n\n\treturn b, id, scdsdata, nil\n}\n\n// ValidateCC returns error if the chaincode is not found or if its not a\n// ChaincodeDeploymentSpec\nfunc (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) error {\n\tif ccpack.sDepSpec == nil {\n\t\treturn errors.New(\"uninitialized package\")\n\t}\n\n\tif ccpack.sDepSpec.ChaincodeDeploymentSpec == nil {\n\t\treturn errors.New(\"signed chaincode deployment spec cannot be nil in a package\")\n\t}\n\n\tif ccpack.depSpec == nil {\n\t\treturn errors.New(\"chaincode deployment spec cannot be nil in a package\")\n\t}\n\n\t// This is a hack. LSCC expects a specific LSCC error when names are invalid so it\n\t// has its own validation code. We can't use that error because of import cycles.\n\t// Unfortunately, we also need to check if what have makes some sort of sense as\n\t// protobuf will gladly deserialize garbage and there are paths where we assume that\n\t// a successful unmarshal means everything works but, if it fails, we try to unmarshal\n\t// into something different.\n\tif !isPrintable(ccdata.Name) {\n\t\treturn fmt.Errorf(\"invalid chaincode name: %q\", ccdata.Name)\n\t}\n\n\tif ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version {\n\t\treturn fmt.Errorf(\"invalid chaincode data %v (%v)\", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/common/ccprovider/sigcdspackage.go#L170-L206","documentation":"Within ValidateCC, after confirming the package was initialized, the code checks that the SignedChaincodeDeploymentSpec actually contains a ChaincodeDeploymentSpec. If sDepSpec.ChaincodeDeploymentSpec is nil, the package is structurally invalid — it claims to be a signed deployment spec but carries no deployment payload. This is more specific than the 'uninitialized package' case.","triggerScenarios":"ValidateCC (via GetCCPackage) is given a package initialized from bytes that decode to a SignedChaincodeDeploymentSpec whose ChaincodeDeploymentSpec field is unset — e.g. a serialized protobuf with only metadata/owner fields populated.","commonSituations":"Hand-crafted or truncated protobuf payloads in uploads/tests; SDKs serializing the wrapper message without embedding the deployment spec; wrong-field assignment when constructing SignedChaincodeDeploymentSpec programmatically.","solutions":["Regenerate the package ensuring ChaincodeDeploymentSpec is populated (proto.Marshal of a real ChaincodeDeploymentSpec) before signing.","Validate input bytes by unmarshalling into SignedChaincodeDeploymentSpec and checking ChaincodeDeploymentSpec != nil before calling GetCCPackage.","Fix the producing tool/SDK so it always embeds the deployment spec in the signed wrapper.","Reject untrusted payloads upstream with a clear message instead of letting GetCCPackage report the generic validation failure."],"exampleFix":"// before\nscds := &pb.SignedChaincodeDeploymentSpec{InstantiationPolicy: policy}\n// after\ncdsBytes, _ := proto.Marshal(cds)\nscds := &pb.SignedChaincodeDeploymentSpec{ChaincodeDeploymentSpec: cdsBytes, InstantiationPolicy: policy}","handlingStrategy":"validation","validationCode":"var scds pb.SignedChaincodeDeploymentSpec\nif err := proto.Unmarshal(bytes, &scds); err != nil {\n    return err\n}\nif scds.ChaincodeDeploymentSpec == nil {\n    return errors.New(\"package rejected: embedded ChaincodeDeploymentSpec is nil\")\n}","typeGuard":"func hasDeploymentSpec(scds *pb.SignedChaincodeDeploymentSpec) bool {\n    return scds != nil && scds.ChaincodeDeploymentSpec != nil && scds.ChaincodeDeploymentSpec.ChaincodeSpec != nil\n}","tryCatchPattern":"if err := pack.ValidateCC(ccdata); err != nil {\n    if strings.Contains(err.Error(), \"signed chaincode deployment spec cannot be nil\") {\n        // regenerate the package with an embedded deployment spec\n    }\n    return err\n}","preventionTips":["Always populate ChaincodeDeploymentSpec (proto.Marshal of a real CDS) in the signed wrapper before signing.","Round-trip test: marshal, unmarshal, and assert the embedded spec is present before uploading.","Reject untrusted packages whose embedded ChaincodeDeploymentSpec is nil.","Keep SDK/tool versions aligned with the Fabric package format."],"tags":["chaincode","package-validation","protobuf","fabric"],"backgroundTag":"missing-deployment-spec","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"}