hyperledger/fabric · error

expected a chain of length at least 2, got %d

Error message

expected a chain of length at least 2, got %d

What it means

getValidationChain expects the verified chain to contain at least the identity certificate plus its issuing CA (root or parent). A chain of length 1 means the certificate verified directly against a trust anchor that is itself the certificate, or the verify options made cert.Verify return a single self-referential entry — so no parent can be located. The library throws this because the subsequent parent-lookup logic requires >=2 entries.

Source

Thrown at msp/mspimpl.go:852

				// found in deployments outside the WebPKI.
				continue
			}
			return false
		}
	}

	return true
}

func (msp *bccspmsp) getValidationChain(cert *x509.Certificate, isIntermediateChain bool) ([]*x509.Certificate, error) {
	validationChain, err := msp.getUniqueValidationChain(cert, msp.getValidityOptsForCert(cert))
	if err != nil {
		return nil, errors.WithMessage(err, "failed getting validation chain")
	}

	// we expect a chain of length at least 2
	if len(validationChain) < 2 {
		return nil, errors.Errorf("expected a chain of length at least 2, got %d", len(validationChain))
	}

	// check that the parent is a leaf of the certification tree
	// if validating an intermediate chain, the first certificate will the parent
	parentPosition := 1
	if isIntermediateChain {
		parentPosition = 0
	}
	if msp.certificationTreeInternalNodesMap[string(validationChain[parentPosition].Raw)] {
		return nil, errors.Errorf("invalid validation chain. Parent certificate should be a leaf of the certification tree [%v]", cert.Raw)
	}
	return validationChain, nil
}

// getCertificationChainIdentifier returns the certification chain identifier of the passed identity within this msp.
// The identifier is computes as the SHA256 of the concatenation of the certificates in the chain.
func (msp *bccspmsp) getCertificationChainIdentifier(id Identity) ([]byte, error) {
	chain, err := msp.getCertificationChain(id)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the identity certificate is issued by a CA distinct from itself; use a proper end-entity cert
  2. Remove the identity/self-signed cert from the MSP cacerts folder
  3. Provide the real root (and intermediates) so the chain is [identity, intermediate?, root]
  4. Re-enroll with fabric-ca to get a chain rooted at the org CA

Example fix

// before
// cacerts contains identityCert.pem (self-signed identity also used as identity)
// after
// cacerts contains rootCA.pem; identity cert issued by rootCA
Defensive patterns

Strategy: validation

Validate before calling

if bytes.Equal(cert.Raw, rootCA.Raw) { return errors.New("identity cert must not be the root CA itself") }

Type guard

func hasIssuer(cert, issuer *x509.Certificate) bool {
	return cert.CheckSignatureFrom(issuer) == nil && !bytes.Equal(cert.Raw, issuer.Raw)
}

Try / catch

chain, err := msp.GetCertificationChain(id)
if err != nil && strings.Contains(err.Error(), "chain of length at least 2") {
	// identity is self-signed or equals a trust anchor: re-enroll
}

Prevention

When it happens

Trigger: getCertificationChainForBCCSPIdentity or getCertifiersIdentifier calls getValidationChain for a certificate whose Verify(opts) result has fewer than 2 certificates — typically when the identity cert is itself the root CA in msp.opts.Roots, or a self-signed cert was added as its own root.

Common situations: Registering a self-signed certificate both as identity and as MSP root; misconfigured MSP where the identity cert was copied into cacerts; validation options that include the identity's own cert as a trust anchor.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/8f2e63128c3d4b55. Report an issue: GitHub.