apache/pulsar · error · IllegalArgumentException
Invalid value for BROKER_CLIENT_TRUST_CERTS_SECRET_NAME…
Error message
Invalid value for BROKER_CLIENT_TRUST_CERTS_SECRET_NAME. Expected a string.
What it means
KubernetesServiceAccountTokenAuthProvider.initialize() validates the function auth config map. If BROKER_CLIENT_TRUST_CERTS_SECRET_NAME is set to a non-String, non-null value (e.g. an Integer, Boolean or Map), the provider deliberately fails fast with IllegalArgumentException because the user explicitly configured this key but with an invalid type.
Solutions
- Set BROKER_CLIENT_TRUST_CERTS_SECRET_NAME to a quoted String value containing the Kubernetes secret name.
- Check the config source (YAML/JSON/env parser) and quote or coerce values so numeric-looking names arrive as strings.
- Log/inspect the exact config value and its Java class before calling initialize to find where the wrong type enters.
Example fix
// before config.put(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME, 12345); // after config.put(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME, String.valueOf(12345));
Defensive patterns
Strategy: validation
Validate before calling
Object v = config.get(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME);
if (v != null && !(v instanceof String)) {
throw new IllegalArgumentException("BROKER_CLIENT_TRUST_CERTS_SECRET_NAME must be a String, got " + v.getClass().getName());
} Type guard
static boolean isStringConfig(Object v) { return v == null || v instanceof String; } Try / catch
try {
provider.initialize(config);
} catch (IllegalArgumentException e) {
log.error("Function auth provider config invalid: {}", e.getMessage());
throw new ConfigValidationException(e);
} Prevention
- Quote string values in YAML/JSON configs even if they look numeric
- Validate config maps against an expected key->type schema before passing to the provider
- Add unit tests for config loading that assert value types
- Log config value classes at debug when building the auth config
When it happens
Trigger: Calling initialize(authConfig) where config.get(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME) returns a non-null object that is not a String — e.g. the config was built programmatically with a number, boolean, or nested collection instead of a secret name string.
Common situations: YAML/JSON tooling parsed the secret name as a number or boolean (e.g. `12345` or `true` unquoted); a config builder passed a wrong-typed value; configuration deserialization coerced the value to an unexpected type.
Related errors
- Invalid value for SERVICE_ACCOUNT_TOKEN_AUDIENCE. Expected…
- Invalid value for SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS…
- Failed to create service for function
- Failed to create statefulset for function
- Failed to delete service for function
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/b96b1969bf0ce5e6.
Report an issue: GitHub.
Appendix: source
Thrown at pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java:87
private static final String DEFAULT_MOUNT_DIR = "/etc/auth";
private static final String FUNCTION_AUTH_TOKEN = "token";
private static final String FUNCTION_CA_CERT = "ca.crt";
private static final String DEFAULT_CERT_PATH = DEFAULT_MOUNT_DIR + "/" + FUNCTION_CA_CERT;
private String brokerTrustCertsSecretName;
private long serviceAccountTokenExpirationSeconds;
private String serviceAccountTokenAudience;
@Override
public void initialize(CoreV1Api coreClient, byte[] caBytes,
java.util.function.Function<FunctionDetails, String> namespaceCustomizerFunc,
Map<String, Object> config) {
setNamespaceProviderFunc(namespaceCustomizerFunc);
Object certSecretName = config.get(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME);
if (certSecretName instanceof String) {
brokerTrustCertsSecretName = (String) certSecretName;
} else if (certSecretName != null) {
// Throw exception because user set this configuration, but it isn't valid.
throw new IllegalArgumentException("Invalid value for " + BROKER_CLIENT_TRUST_CERTS_SECRET_NAME
+ ". Expected a string.");
}
Object tokenExpirationSeconds = config.get(SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS);
if (tokenExpirationSeconds instanceof Long) {
serviceAccountTokenExpirationSeconds = (Long) tokenExpirationSeconds;
} else if (tokenExpirationSeconds instanceof String) {
try {
serviceAccountTokenExpirationSeconds = Long.parseLong((String) tokenExpirationSeconds);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid value for " + SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS
+ ". Expected a long.");
}
} else if (tokenExpirationSeconds != null) {
// Throw exception because user set this configuration, but it isn't valid.
throw new IllegalArgumentException("Invalid value for " + SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS
+ ". Expected a long.");
}
Object tokenAudience = config.get(SERVICE_ACCOUNT_TOKEN_AUDIENCE);View on GitHub (pinned to 820761864e)