{"record":{"id":"b96b1969bf0ce5e6","repo":"apache/pulsar","slug":"invalid-value-for-broker-client-trust-certs-secret","errorCode":null,"errorMessage":"Invalid value for BROKER_CLIENT_TRUST_CERTS_SECRET_NAME. Expected a string.","messagePattern":"Invalid value for BROKER_CLIENT_TRUST_CERTS_SECRET_NAME\\. Expected a string\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java","lineNumber":87,"sourceCode":"    private static final String DEFAULT_MOUNT_DIR = \"/etc/auth\";\n    private static final String FUNCTION_AUTH_TOKEN = \"token\";\n    private static final String FUNCTION_CA_CERT = \"ca.crt\";\n    private static final String DEFAULT_CERT_PATH = DEFAULT_MOUNT_DIR + \"/\" + FUNCTION_CA_CERT;\n    private String brokerTrustCertsSecretName;\n    private long serviceAccountTokenExpirationSeconds;\n    private String serviceAccountTokenAudience;\n\n    @Override\n    public void initialize(CoreV1Api coreClient, byte[] caBytes,\n                           java.util.function.Function<FunctionDetails, String> namespaceCustomizerFunc,\n                           Map<String, Object> config) {\n        setNamespaceProviderFunc(namespaceCustomizerFunc);\n        Object certSecretName = config.get(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME);\n        if (certSecretName instanceof String) {\n            brokerTrustCertsSecretName = (String) certSecretName;\n        } else if (certSecretName != null) {\n            // Throw exception because user set this configuration, but it isn't valid.\n            throw new IllegalArgumentException(\"Invalid value for \" + BROKER_CLIENT_TRUST_CERTS_SECRET_NAME\n                    + \". Expected a string.\");\n        }\n        Object tokenExpirationSeconds = config.get(SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS);\n        if (tokenExpirationSeconds instanceof Long) {\n            serviceAccountTokenExpirationSeconds = (Long) tokenExpirationSeconds;\n        } else if (tokenExpirationSeconds instanceof String) {\n            try {\n                serviceAccountTokenExpirationSeconds = Long.parseLong((String) tokenExpirationSeconds);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\"Invalid value for \" + SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS\n                        + \". Expected a long.\");\n            }\n        } else if (tokenExpirationSeconds != null) {\n            // Throw exception because user set this configuration, but it isn't valid.\n            throw new IllegalArgumentException(\"Invalid value for \" + SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS\n                    + \". Expected a long.\");\n        }\n        Object tokenAudience = config.get(SERVICE_ACCOUNT_TOKEN_AUDIENCE);","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java#L69-L105","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconfig.put(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME, 12345);\n// after\nconfig.put(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME, String.valueOf(12345));","handlingStrategy":"validation","validationCode":"Object v = config.get(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME);\nif (v != null && !(v instanceof String)) {\n    throw new IllegalArgumentException(\"BROKER_CLIENT_TRUST_CERTS_SECRET_NAME must be a String, got \" + v.getClass().getName());\n}","typeGuard":"static boolean isStringConfig(Object v) { return v == null || v instanceof String; }","tryCatchPattern":"try {\n    provider.initialize(config);\n} catch (IllegalArgumentException e) {\n    log.error(\"Function auth provider config invalid: {}\", e.getMessage());\n    throw new ConfigValidationException(e);\n}","preventionTips":["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"],"tags":["kubernetes","functions-runtime","config-validation"],"backgroundTag":"invalid-config-value-type","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}