grpc/grpc-java · error · CertificateException
Spiffe Trust Map doesn't contain trust domain '%s' from peer
Error message
Spiffe Trust Map doesn't contain trust domain '%s' from peer leaf certificate
What it means
Thrown by XdsX509TrustManager.chooseDelegate when a SPIFFE trust map is configured, the peer's SPIFFE ID was extracted successfully, but the ID's trust domain is not a key in spiffeTrustMapDelegates. The manager refuses to pick a trust manager for an unknown trust domain, failing the TLS handshake rather than silently falling back.
Source
Thrown at xds/src/main/java/io/grpc/xds/internal/security/trust/XdsX509TrustManager.java:329
String hostName = sniHostName.getAsciiName();
sniNamesToMatch.add(StringMatcher.newBuilder().setExact(hostName).build());
}
}
}
}
return sniNamesToMatch;
}
private X509ExtendedTrustManager chooseDelegate(X509Certificate[] chain)
throws CertificateException {
if (spiffeTrustMapDelegates != null) {
Optional<SpiffeUtil.SpiffeId> spiffeId = SpiffeUtil.extractSpiffeId(chain);
if (!spiffeId.isPresent()) {
throw new CertificateException("Failed to extract SPIFFE ID from peer leaf certificate");
}
String trustDomain = spiffeId.get().getTrustDomain();
if (!spiffeTrustMapDelegates.containsKey(trustDomain)) {
throw new CertificateException(String.format("Spiffe Trust Map doesn't contain trust"
+ " domain '%s' from peer leaf certificate", trustDomain));
}
return spiffeTrustMapDelegates.get(trustDomain);
} else {
return delegate;
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
if (spiffeTrustMapDelegates != null) {
Set<X509Certificate> result = new HashSet<>();
for (X509ExtendedTrustManager tm: spiffeTrustMapDelegates.values()) {
result.addAll(Arrays.asList(tm.getAcceptedIssuers()));
}
return result.toArray(new X509Certificate[0]);
}
return delegate.getAcceptedIssuers();View on GitHub (pinned to 64daddc1f3)
Solutions
- Add an entry for the peer's trust domain (exactly as it appears in the SPIFFE URI) to the SPIFFE trust map configuration, backed by a trust manager with that domain's root CA
- Fix key typos: compare the map keys with the trust domain printed in the error message (case-sensitive exact match)
- If the peer's trust domain was renamed, update its certs or the map key to the new domain name
- If the peer should not be trusted at all, block it at the network/load-balancer layer instead of adding its domain to the trust map
Example fix
// before: only local domain configured
Map<String, X509ExtendedTrustManager> delegates =
Map.of("local-td", localTrustManager);
// after: include the federated domain from the error
Map<String, X509ExtendedTrustManager> delegates = Map.of(
"local-td", localTrustManager,
"remote-td", remoteTrustManager); Defensive patterns
Strategy: validation
Validate before calling
// Check that every expected trust domain exists in the trust map before wiring delegates
static void requireTrustDomains(Map<String, X509ExtendedTrustManager> delegates,
Collection<String> expectedDomains) {
for (String d : expectedDomains) {
if (!delegates.containsKey(d)) {
throw new IllegalArgumentException("Trust map missing trust domain: " + d);
}
}
} Type guard
static boolean trustDomainKnown(Map<String, X509ExtendedTrustManager> map, String spiffeUri) {
int start = "spiffe://".length();
int slash = spiffeUri.indexOf('/', start);
return slash > start && map.containsKey(spiffeUri.substring(start, slash));
} Try / catch
try {
mtlsCall();
} catch (SSLHandshakeException e) {
if (e.getCause() instanceof CertificateException
&& e.getCause().getMessage().contains("Spiffe Trust Map doesn't contain trust domain")) {
String td = extractTrustDomain(e.getCause().getMessage());
log.error("Add trust domain '" + td + "' to the SPIFFE trust map or reject the peer");
}
throw e;
} Prevention
- Generate trust-map keys from the same source as the SPIFFE IDs to avoid typos
- When federating a new cluster/org, add its trust domain and root CA before enabling traffic
- Log trust domains from incoming SPIFFE IDs in a pre-production canary to discover missing entries early
When it happens
Trigger: checkClientTrusted/checkServerTrusted is called with a peer whose SPIFFE URI SAN has trust domain X (e.g. spiffe://other-td/...) while the configured trust map only contains other domains; the error message names the offending trust domain.
Common situations: Cross-cluster/cross-org mTLS where the peer belongs to a trust domain not added to the local trust map; trust domain renamed during migration; typo in the trust map key (map keys must exactly match the SPIFFE URI's trust-domain component); federating a new environment without updating the mesh config.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to extract SPIFFE ID from peer leaf certificate
- Peer certificate SAN check failed
- Peer certificate(s) missing
- Multiple URI SAN values found in the leaf cert.
- ${validationResult.getValidationDetails()} (server-provided
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/03e8227c9dd9768f.
Report an issue: GitHub.