{"record":{"id":"70f65ec3399b9495","repo":"apache/pulsar","slug":"invalid-value-for-service-account-token-audience","errorCode":null,"errorMessage":"Invalid value for SERVICE_ACCOUNT_TOKEN_AUDIENCE. Expected a string.","messagePattern":"Invalid value for SERVICE_ACCOUNT_TOKEN_AUDIENCE\\. 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":109,"sourceCode":"        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);\n        if (tokenAudience instanceof String) {\n            serviceAccountTokenAudience = (String) tokenAudience;\n        } else if (tokenAudience != null) {\n            throw new IllegalArgumentException(\"Invalid value for \" + SERVICE_ACCOUNT_TOKEN_AUDIENCE\n                    + \". Expected a string.\");\n        }\n    }\n\n    @Override\n    public void configureAuthenticationConfig(AuthenticationConfig authConfig,\n                                              Optional<FunctionAuthData> functionAuthData) {\n        authConfig.setClientAuthenticationPlugin(AuthenticationToken.class.getName());\n        authConfig.setClientAuthenticationParameters(Paths.get(DEFAULT_MOUNT_DIR, FUNCTION_AUTH_TOKEN)\n                .toUri().toString());\n        if (StringUtil.isNotBlank(brokerTrustCertsSecretName)) {\n            authConfig.setTlsTrustCertsFilePath(DEFAULT_CERT_PATH);\n        }\n    }\n\n    /**\n     * No need to cache anything. Kubernetes generates the token used for authentication.\n     */","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java#L91-L127","documentation":"initialize() validates SERVICE_ACCOUNT_TOKEN_AUDIENCE and throws IllegalArgumentException when the key is set to a non-String, non-null value. The token audience must be a plain string identifying the audience for the projected service-account token.","triggerScenarios":"SERVICE_ACCOUNT_TOKEN_AUDIENCE is provided as an Integer, Boolean, List, or Map (e.g. a list of audiences) instead of a single String.","commonSituations":"Users provide multiple audiences as a YAML list; audience names parsed as numbers/booleans; programmatic config built with wrong-typed values.","solutions":["Set SERVICE_ACCOUNT_TOKEN_AUDIENCE to a single quoted String value.","If multiple audiences are needed, configure one per provider instance or pass the primary audience only.","Normalize/serialize lists to a single string before building the config map."],"exampleFix":"// before\nconfig.put(SERVICE_ACCOUNT_TOKEN_AUDIENCE, List.of(\"broker\", \"proxy\"));\n// after\nconfig.put(SERVICE_ACCOUNT_TOKEN_AUDIENCE, \"broker\");","handlingStrategy":"validation","validationCode":"Object v = config.get(SERVICE_ACCOUNT_TOKEN_AUDIENCE);\nif (v != null && !(v instanceof String)) {\n    throw new IllegalArgumentException(\"SERVICE_ACCOUNT_TOKEN_AUDIENCE must be a single String, got \" + v.getClass().getName());\n}","typeGuard":"static boolean isStringOrNull(Object v) { return v == null || v instanceof String; }","tryCatchPattern":"try {\n    provider.initialize(config);\n} catch (IllegalArgumentException e) {\n    log.error(\"Token audience must be a string: {}\", e.getMessage());\n    throw new ConfigValidationException(e);\n}","preventionTips":["Provide one audience string, not a list; configure multiple audiences separately if supported","Quote audience values in YAML","Validate config map value types before calling initialize","Keep audience names alphanumeric to avoid parser coercion"],"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-14T05:17:10.506Z"}