{"record":{"id":"03e8227c9dd9768f","repo":"grpc/grpc-java","slug":"spiffe-trust-map-doesn-t-contain-trust-domain-s","errorCode":null,"errorMessage":"Spiffe Trust Map doesn't contain trust domain '%s' from peer leaf certificate","messagePattern":"Spiffe Trust Map doesn't contain trust domain '(.+?)' from peer leaf certificate","errorType":"validation","errorClass":"CertificateException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/security/trust/XdsX509TrustManager.java","lineNumber":329,"sourceCode":"            String hostName = sniHostName.getAsciiName();\n            sniNamesToMatch.add(StringMatcher.newBuilder().setExact(hostName).build());\n          }\n        }\n      }\n    }\n    return sniNamesToMatch;\n  }\n\n  private X509ExtendedTrustManager chooseDelegate(X509Certificate[] chain)\n      throws CertificateException {\n    if (spiffeTrustMapDelegates != null) {\n      Optional<SpiffeUtil.SpiffeId> spiffeId = SpiffeUtil.extractSpiffeId(chain);\n      if (!spiffeId.isPresent()) {\n        throw new CertificateException(\"Failed to extract SPIFFE ID from peer leaf certificate\");\n      }\n      String trustDomain = spiffeId.get().getTrustDomain();\n      if (!spiffeTrustMapDelegates.containsKey(trustDomain)) {\n        throw new CertificateException(String.format(\"Spiffe Trust Map doesn't contain trust\"\n            + \" domain '%s' from peer leaf certificate\", trustDomain));\n      }\n      return spiffeTrustMapDelegates.get(trustDomain);\n    } else {\n      return delegate;\n    }\n  }\n\n  @Override\n  public X509Certificate[] getAcceptedIssuers() {\n    if (spiffeTrustMapDelegates != null) {\n      Set<X509Certificate> result = new HashSet<>();\n      for (X509ExtendedTrustManager tm: spiffeTrustMapDelegates.values()) {\n        result.addAll(Arrays.asList(tm.getAcceptedIssuers()));\n      }\n      return result.toArray(new X509Certificate[0]);\n    }\n    return delegate.getAcceptedIssuers();","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/security/trust/XdsX509TrustManager.java#L311-L347","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: only local domain configured\nMap<String, X509ExtendedTrustManager> delegates =\n    Map.of(\"local-td\", localTrustManager);\n\n// after: include the federated domain from the error\nMap<String, X509ExtendedTrustManager> delegates = Map.of(\n    \"local-td\", localTrustManager,\n    \"remote-td\", remoteTrustManager);","handlingStrategy":"validation","validationCode":"// Check that every expected trust domain exists in the trust map before wiring delegates\nstatic void requireTrustDomains(Map<String, X509ExtendedTrustManager> delegates,\n    Collection<String> expectedDomains) {\n  for (String d : expectedDomains) {\n    if (!delegates.containsKey(d)) {\n      throw new IllegalArgumentException(\"Trust map missing trust domain: \" + d);\n    }\n  }\n}","typeGuard":"static boolean trustDomainKnown(Map<String, X509ExtendedTrustManager> map, String spiffeUri) {\n  int start = \"spiffe://\".length();\n  int slash = spiffeUri.indexOf('/', start);\n  return slash > start && map.containsKey(spiffeUri.substring(start, slash));\n}","tryCatchPattern":"try {\n  mtlsCall();\n} catch (SSLHandshakeException e) {\n  if (e.getCause() instanceof CertificateException\n      && e.getCause().getMessage().contains(\"Spiffe Trust Map doesn't contain trust domain\")) {\n    String td = extractTrustDomain(e.getCause().getMessage());\n    log.error(\"Add trust domain '\" + td + \"' to the SPIFFE trust map or reject the peer\");\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["mtls","spiffe","certificate-validation","xds","trust-domain"],"backgroundTag":"record-not-found","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}