grpc/grpc-java · error · NullPointerException

either 'ca_certificate_file' or 'spiffe_trust_bundle_map_fil

Error message

either 'ca_certificate_file' or 'spiffe_trust_bundle_map_file' is required in the config

What it means

FileWatcherCertificateProviderProvider.validateAndTranslateConfig validates the JSON config for the file_watcher certificate provider. When SPIFFE support is enabled, the config must supply at least one trust anchor source: a root CA certificate file ('ca_certificate_file') or a SPIFFE trust bundle map file ('spiffe_trust_bundle_map_file'). If neither key is present, a NullPointerException with this message is thrown (misleading exception type, but it signals a missing required config field).

Source

Thrown at xds/src/main/java/io/grpc/xds/internal/security/certprovider/FileWatcherCertificateProviderProvider.java:110

        configObj.refrehInterval,
        scheduledExecutorServiceFactory.create(),
        timeProvider);
  }

  private static String checkForNullAndGet(Map<String, ?> map, String key) {
    return checkNotNull(JsonUtil.getString(map, key), "'" + key + "' is required in the config");
  }

  private static Config validateAndTranslateConfig(Object config) {
    checkArgument(config instanceof Map, "Only Map supported for config");
    @SuppressWarnings("unchecked") Map<String, ?> map = (Map<String, ?>)config;

    Config configObj = new Config();
    configObj.certFile = checkForNullAndGet(map, CERT_FILE_KEY);
    configObj.keyFile = checkForNullAndGet(map, KEY_FILE_KEY);
    if (enableSpiffe) {
      if (!map.containsKey(ROOT_FILE_KEY) && !map.containsKey(SPIFFE_TRUST_MAP_FILE_KEY)) {
        throw new NullPointerException(
            String.format("either '%s' or '%s' is required in the config",
                ROOT_FILE_KEY, SPIFFE_TRUST_MAP_FILE_KEY));
      }
      if (map.containsKey(SPIFFE_TRUST_MAP_FILE_KEY)) {
        configObj.spiffeTrustMapFile = JsonUtil.getString(map, SPIFFE_TRUST_MAP_FILE_KEY);
      } else {
        configObj.rootFile = JsonUtil.getString(map, ROOT_FILE_KEY);
      }
    } else {
      configObj.rootFile = checkForNullAndGet(map, ROOT_FILE_KEY);
    }
    String refreshIntervalString = JsonUtil.getString(map, REFRESH_INTERVAL_KEY);
    if (refreshIntervalString != null) {
      try {
        Duration duration = Durations.parse(refreshIntervalString);
        configObj.refrehInterval = duration.getSeconds();
        checkArgument(configObj.refrehInterval > 0L, "refreshInterval needs to be greater than 0");
      } catch (ParseException e) {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Add 'ca_certificate_file': '<path to root CA pem>' to the file_watcher provider config
  2. Alternatively add 'spiffe_trust_bundle_map_file': '<path to trust bundle JSON>' for SPIFFE trust domains
  3. Verify the bootstrap certProviders JSON contains one of the two keys when SPIFFE is enabled
  4. Fix the control plane or deployment templates that generate the provider config to always include a trust anchor

Example fix

// before
{"certificate_file": "cert.pem", "private_key_file": "key.pem"}
// after
{"certificate_file": "cert.pem", "private_key_file": "key.pem", "ca_certificate_file": "ca.pem"}
Defensive patterns

Strategy: validation

Validate before calling

// Validate file_watcher provider config JSON before registration
boolean validTrustSource(Map<String, ?> map) {
  return map.containsKey("ca_certificate_file") || map.containsKey("spiffe_trust_bundle_map_file");
}
if (!validTrustSource(config)) throw new IllegalArgumentException("file_watcher config needs ca_certificate_file or spiffe_trust_bundle_map_file");

Try / catch

try {
  registry.register(fileWatcherProvider);
} catch (NullPointerException e) {
  if (e.getMessage() != null && e.getMessage().contains("is required in the config")) {
    logger.error("file_watcher config missing trust anchor: add ca_certificate_file or spiffe_trust_bundle_map_file", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Enabling SPIFFE and registering a file_watcher provider whose config JSON contains certificate_file and private_key_file but lacks both 'ca_certificate_file' and 'spiffe_trust_bundle_map_file'; thrown from validateAndTranslateConfig during config parsing (called via configObj).

Common situations: Cert configs copied from non-SPIFFE examples missing trust roots; bootstrap certProviders entries where only client cert/key files were specified; migration to SPIFFE trust bundles where the root file key was renamed.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/a8eb0d9cc863ae1a. Report an issue: GitHub.