grpc/grpc-java · critical · XdsInitializationException

Invalid bootstrap: server ${serverUri} with 'channel_creds'

Error message

Invalid bootstrap: server ${serverUri} with 'channel_creds' type unspecified

What it means

Thrown by GrpcBootstrapperImpl.parseChannelCredentials when a channel_creds entry in the bootstrap JSON has no 'type' field. The type field is mandatory because it selects which XdsCredentialsProvider parses the entry's config. Without it the credential entry is ambiguous, so bootstrap parsing fails immediately.

Source

Thrown at xds/src/main/java/io/grpc/xds/GrpcBootstrapperImpl.java:154

          "Invalid bootstrap: server " + serverUri + " 'channel_creds' required");
    }
    ConfiguredChannelCredentials credentials =
        parseChannelCredentials(JsonUtil.checkObjectList(rawChannelCredsList), serverUri);
    if (credentials == null) {
      throw new XdsInitializationException(
          "Server " + serverUri + ": no supported channel credentials found");
    }
    return credentials;
  }

  @Nullable
  private static ConfiguredChannelCredentials parseChannelCredentials(List<Map<String, ?>> jsonList,
          String serverUri)
      throws XdsInitializationException {
    for (Map<String, ?> channelCreds : jsonList) {
      String type = JsonUtil.getString(channelCreds, "type");
      if (type == null) {
        throw new XdsInitializationException(
            "Invalid bootstrap: server " + serverUri + " with 'channel_creds' type unspecified");
      }
      XdsCredentialsProvider provider =  XdsCredentialsRegistry.getDefaultRegistry()
          .getProvider(type);
      if (provider != null) {
        Map<String, ?> config = JsonUtil.getObject(channelCreds, "config");
        if (config == null) {
          config = ImmutableMap.of();
        }

        ChannelCredentials creds = provider.newChannelCredentials(config);
        if (creds == null) {
          return null;
        }
        return ConfiguredChannelCredentials.create(creds, new JsonChannelCredsConfig(type, config));
      }
    }
    return null;

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Add the required "type" field to every channel_creds entry in the bootstrap file.
  2. Validate the bootstrap JSON against the gRPC xDS bootstrap schema before deployment.
  3. Check for JSON quoting/escaping mistakes that silently dropped the type key during templating.

Example fix

// before (bootstrap.json)
"channel_creds": [{"config": {"cert_file": "ca.pem"}}]
// after
"channel_creds": [{"type": "google_default", "config": {"cert_file": "ca.pem"}}]
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every channel_creds entry declares a type
for (Map<String, ?> entry : rawChannelCreds) {
  if (JsonUtil.getString(entry, "type") == null) {
    throw new IllegalArgumentException("channel_creds entry missing 'type'");
  }
}

Prevention

When it happens

Trigger: Bootstrap file contains a servers[].channel_creds entry like {"config": {...}} with only a config object and no "type" key; typically from a hand-written or malformed bootstrap file.

Common situations: Manually editing bootstrap JSON and dropping the type key; template-generated configs with an unfilled placeholder; copying Envoy credential configs that nest type differently.

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/9adc656cf3160d22. Report an issue: GitHub.