nats-io/nats-server · error
incomplete cert chain, got %d, want at least %d
Error message
incomplete cert chain, got %d, want at least %d
What it means
GetOCSPStatus requires at least a leaf and its issuer in the first verified chain to check the OCSP response signature. If the chain has fewer than 2 certificates, validation cannot proceed and this error reports the actual length found.
Source
Thrown at internal/ocsp/ocsp.go:237
if err != nil {
t.Fatal(err)
}
block, _ := pem.Decode(data)
if block == nil {
t.Fatalf("failed to decode PEM %s", pemPath)
}
return block
}
func GetOCSPStatus(s tls.ConnectionState) (*ocsp.Response, error) {
if len(s.VerifiedChains) == 0 {
return nil, fmt.Errorf("missing TLS verified chains")
}
chain := s.VerifiedChains[0]
if got, want := len(chain), 2; got < want {
return nil, fmt.Errorf("incomplete cert chain, got %d, want at least %d", got, want)
}
leaf, issuer := chain[0], chain[1]
resp, err := ocsp.ParseResponseForCert(s.OCSPResponse, leaf, issuer)
if err != nil {
return nil, fmt.Errorf("failed to parse OCSP response: %w", err)
}
if err := resp.CheckSignatureFrom(issuer); err != nil {
return resp, err
}
return resp, nil
}
func SetOCSPStatus(t *testing.T, ocspURL, certPEM string, status int) {
t.Helper()
cert := parseCertPEM(t, certPEM)
View on GitHub (pinned to 3a66a489d2)
Solutions
- Ensure the client sends (or the server's cert pool supplies) the issuer certificate so the chain has at least leaf + issuer
- If using self-signed test certs, build a two-cert chain (root CA + leaf) instead of a single self-signed leaf
- Guard with a length check on VerifiedChains[0] before calling GetOCSPStatus
Example fix
// before
chain := [][]*x509.Certificate{{leaf}}
// after
chain := [][]*x509.Certificate{{leaf, caCert}} Defensive patterns
Strategy: type-guard
Validate before calling
cs := conn.ConnectionState()
if len(cs.VerifiedChains) == 0 || len(cs.VerifiedChains[0]) < 2 {
return errors.New("chain too short for OCSP check (need leaf + issuer)")
} Type guard
func hasLeafAndIssuer(cs tls.ConnectionState) bool {
return len(cs.VerifiedChains) > 0 && len(cs.VerifiedChains[0]) >= 2
} Try / catch
resp, err := GetOCSPStatus(cs)
if err != nil {
if strings.HasPrefix(err.Error(), "incomplete cert chain") {
return nil, errOCSPNotPossible
}
return err
} Prevention
- Configure clients to send the full chain (leaf + intermediates)
- Include intermediates in the server's RootCAs/ClientCAs pool
- Use test chains with at least two certs
When it happens
Trigger: Calling GetOCSPStatus with a ConnectionState whose VerifiedChains[0] contains only the leaf cert (len < 2) — e.g. a self-signed or directly trusted leaf with no issuer appended.
Common situations: Client presenting a self-signed certificate trusted as a root; minimal test chains built with only one cert; RootCAs pool configured so only the leaf verifies without issuer in chain.
Related errors
- invalid issuer configuration: %w
- no issuers found
- invalid chain link
- no available OCSP servers
- unable to plug TLS verify connection, config is nil
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/1d8c50c6a83e2745.
Report an issue: GitHub.