{"record":{"id":"b5b712ad5f3aa1cb","repo":"hyperledger/fabric","slug":"this-msp-only-supports-a-single-validation-chain","errorCode":null,"errorMessage":"this MSP only supports a single validation chain, got %d","messagePattern":"this MSP only supports a single validation chain, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"msp/mspimpl.go","lineNumber":740,"sourceCode":"\n\treturn msp.getValidationChain(id.cert, false)\n}\n\nfunc (msp *bccspmsp) getUniqueValidationChain(cert *x509.Certificate, opts x509.VerifyOptions) ([]*x509.Certificate, error) {\n\t// ask golang to validate the cert for us based on the options that we've built at setup time\n\tif msp.opts == nil {\n\t\treturn nil, errors.New(\"the supplied identity has no verify options\")\n\t}\n\tvalidationChains, err := cert.Verify(opts)\n\tif err != nil {\n\t\treturn nil, errors.WithMessage(err, \"the supplied identity is not valid\")\n\t}\n\n\t// we only support a single validation chain;\n\t// if there's more than one then there might\n\t// be unclarity about who owns the identity\n\tif len(validationChains) != 1 {\n\t\treturn nil, errors.Errorf(\"this MSP only supports a single validation chain, got %d\", len(validationChains))\n\t}\n\n\t// Make the additional verification checks that were done in Go 1.14.\n\terr = verifyLegacyNameConstraints(validationChains[0])\n\tif err != nil {\n\t\treturn nil, errors.WithMessage(err, \"the supplied identity is not valid\")\n\t}\n\n\treturn validationChains[0], nil\n}\n\nvar (\n\toidExtensionSubjectAltName  = asn1.ObjectIdentifier{2, 5, 29, 17}\n\toidExtensionNameConstraints = asn1.ObjectIdentifier{2, 5, 29, 30}\n)\n\n// verifyLegacyNameConstraints exercises the name constraint validation rules\n// that were part of the certificate verification process in Go 1.14.","sourceCodeStart":722,"sourceCodeEnd":758,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/msp/mspimpl.go#L722-L758","documentation":"Golang's cert.Verify may return multiple chains if the trust anchors allow more than one path to a root. This MSP requires unambiguous ownership of an identity, so it rejects any identity (or CA) with more than one validation chain, reporting how many chains were found.","triggerScenarios":"Validating a certificate that chains to the MSP root via two different paths — e.g. the same root CA trust anchor appears in both cacerts and intermediatescerts, or two overlapping root/intermediate CAs both cover the cert's chain — causing len(validationChains) != 1 during validateIdentity/sanitizeCert/finalizeSetupCAs.","commonSituations":"Copying the same root cert into both the root and intermediate cert folders of the MSP directory; two orgs sharing root CAs; adding redundant trust anchors after a CA migration; Go crypto adding alternative chain paths after trust store changes.","solutions":["Remove duplicate or overlapping certificates from the MSP cacerts and intermediatescerts folders so exactly one chain exists","Ensure intermediate CA certs are in intermediatescerts, not duplicated in cacerts","Regenerate the MSP directory with cryptogen or fabric-ca so each cert has a single trust path","Trim the trust anchor set to only the specific org root that issued the identity"],"exampleFix":"// before\n// cacerts: [rootA.pem, rootB.pem], intermediatescerts: [rootA.pem]  -> 2 chains\n// after\n// cacerts: [rootA.pem], intermediatescerts: [intermediateA.pem]  -> 1 chain","handlingStrategy":"validation","validationCode":"// before setup, dedupe trust anchors and ensure roots/intermediates don't overlap:\nseen := map[string]bool{}\nfor _, c := range roots { seen[string(c.Raw)] = true }\nfor _, c := range intermediates { if seen[string(c.Raw)] { return errors.New(\"duplicate cert in roots and intermediates\") } }","typeGuard":null,"tryCatchPattern":"err := id.Validate()\nif err != nil && strings.Contains(err.Error(), \"single validation chain\") {\n\t// inspect MSP cert folders for duplicates/overlapping CAs\n}","preventionTips":["Keep cacerts to true root CAs only; never place an intermediate in cacerts","Deduplicate PEM files across cacerts/intermediatescerts during MSP packaging","After CA migrations, rebuild the MSP directory rather than incrementally appending certs"],"tags":["x509","msp","fabric","trust-chain"],"backgroundTag":"ambiguous-certificate-chain","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"}