t8y2/dbx · error

JKS truststore contains no certificates

Error message

JKS truststore contains no certificates

What it means

loadTrustStore parses a JKS truststore and collects its embedded certificates; if it finds none, it refuses to build a TLS config because a truststore with zero certificates cannot verify any server. This guards against silently creating a TLS connection with an empty trust anchor set.

Source

Thrown at agents/drivers/hive-go/zookeeper_tls.go:111

					return nil, parseErr
				}
				certificates = append(certificates, certificate)
			case store.IsPrivateKeyEntry(alias):
				chain, getErr := store.GetPrivateKeyEntryCertificateChain(alias)
				if getErr != nil {
					return nil, getErr
				}
				for _, entry := range chain {
					certificate, parseErr := x509.ParseCertificate(entry.Content)
					if parseErr != nil {
						return nil, parseErr
					}
					certificates = append(certificates, certificate)
				}
			}
		}
		if len(certificates) == 0 {
			return nil, errors.New("JKS truststore contains no certificates")
		}
		return certificates, nil
	default:
		return nil, fmt.Errorf("unsupported store type %q", storeType)
	}
}

func loadClientKeyStore(path, password, storeType string) (tls.Certificate, error) {
	contents, err := os.ReadFile(path)
	if err != nil {
		return tls.Certificate{}, err
	}
	switch normalizedStoreType(storeType, path) {
	case "PEM":
		return tls.X509KeyPair(contents, contents)
	case "PKCS12":
		privateKey, certificate, chain, err := pkcs12.DecodeChain(contents, password)
		if err != nil {

View on GitHub (pinned to c0390bff16)

Solutions

  1. Rebuild the truststore to contain the CA certificate chain: keytool -importcert -alias ca -file ca.pem -keystore truststore.jks
  2. Verify the truststore password is correct — wrong passwords cause entries to be skipped
  3. Confirm the file is a JKS truststore (not PKCS12) and matches the configured storeType
  4. Check the file's integrity after deployment (size, keytool -list output shows trustedCertEntry entries)

Example fix

// before
truststore.jks created with:
keytool -genkeypair -keystore truststore.jks  // contains only a private key
// after
keytool -importcert -alias rootca -file ca-cert.pem -keystore truststore.jks \
  -storepass changeit -noprompt
keytool -list -keystore truststore.jks  // must show trustedCertEntry
Defensive patterns

Strategy: validation

Validate before calling

// Go: precheck truststore before building TLS config
func validateTruststore(path, password string) error {
    f, err := os.Open(path)
    if err != nil { return err }
    defer f.Close()
    ks := jks.New(sha1.New)
    if err := ks.Parse(f, []byte(password)); err != nil { return err }
    if len(ks.CertEntries) == 0 { return errors.New("truststore has no certs") }
    return nil
}

Try / catch

certs, err := loadTrustStore(path, password, "JKS")
if err != nil && strings.Contains(err.Error(), "no certificates") {
    return fmt.Errorf("truststore %s has no CAs; re-import the CA chain: %w", path, err)
}

Prevention

When it happens

Trigger: Calling buildTLSConfig/buildZooKeeperTLSConfig with a JKS file that contains only keys/secret entries, is corrupt, is password-protected with the wrong password (entries silently skipped), or is an empty file.

Common situations: Pointing tls.truststore at a keystore instead of a truststore; JKS exported without the CA chain; wrong truststore password so entries fail to decrypt; file truncated during deployment/upload.

Understand the failure class

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/fe44eb4b99b150dd. Report an issue: GitHub.