apache/pulsar · error · IllegalArgumentException

Invalid value for SERVICE_ACCOUNT_TOKEN_AUDIENCE. Expected a

Error message

Invalid value for SERVICE_ACCOUNT_TOKEN_AUDIENCE. Expected a string.

What it means

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.

Source

Thrown at pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java:109

        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);
        if (tokenAudience instanceof String) {
            serviceAccountTokenAudience = (String) tokenAudience;
        } else if (tokenAudience != null) {
            throw new IllegalArgumentException("Invalid value for " + SERVICE_ACCOUNT_TOKEN_AUDIENCE
                    + ". Expected a string.");
        }
    }

    @Override
    public void configureAuthenticationConfig(AuthenticationConfig authConfig,
                                              Optional<FunctionAuthData> functionAuthData) {
        authConfig.setClientAuthenticationPlugin(AuthenticationToken.class.getName());
        authConfig.setClientAuthenticationParameters(Paths.get(DEFAULT_MOUNT_DIR, FUNCTION_AUTH_TOKEN)
                .toUri().toString());
        if (StringUtil.isNotBlank(brokerTrustCertsSecretName)) {
            authConfig.setTlsTrustCertsFilePath(DEFAULT_CERT_PATH);
        }
    }

    /**
     * No need to cache anything. Kubernetes generates the token used for authentication.
     */

View on GitHub (pinned to 820761864e)

Solutions

  1. Set SERVICE_ACCOUNT_TOKEN_AUDIENCE to a single quoted String value.
  2. If multiple audiences are needed, configure one per provider instance or pass the primary audience only.
  3. Normalize/serialize lists to a single string before building the config map.

Example fix

// before
config.put(SERVICE_ACCOUNT_TOKEN_AUDIENCE, List.of("broker", "proxy"));
// after
config.put(SERVICE_ACCOUNT_TOKEN_AUDIENCE, "broker");
Defensive patterns

Strategy: validation

Validate before calling

Object v = config.get(SERVICE_ACCOUNT_TOKEN_AUDIENCE);
if (v != null && !(v instanceof String)) {
    throw new IllegalArgumentException("SERVICE_ACCOUNT_TOKEN_AUDIENCE must be a single String, got " + v.getClass().getName());
}

Type guard

static boolean isStringOrNull(Object v) { return v == null || v instanceof String; }

Try / catch

try {
    provider.initialize(config);
} catch (IllegalArgumentException e) {
    log.error("Token audience must be a string: {}", e.getMessage());
    throw new ConfigValidationException(e);
}

Prevention

When it happens

Trigger: SERVICE_ACCOUNT_TOKEN_AUDIENCE is provided as an Integer, Boolean, List, or Map (e.g. a list of audiences) instead of a single String.

Common situations: Users provide multiple audiences as a YAML list; audience names parsed as numbers/booleans; programmatic config built with wrong-typed values.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/70f65ec3399b9495. Report an issue: GitHub.