apache/pulsar · error · IllegalArgumentException
Function tenant cannot be null
Error message
Function tenant cannot be null
What it means
FunctionConfigUtils.doCommonChecks validates a function's FunctionConfig before it can be created or updated. The first mandatory field is the tenant, the top-level namespace grouping in Pulsar. If tenant is null or empty, validation fails immediately with this IllegalArgumentException so an incomplete function config never reaches the broker.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:791
if (functionConfig.getMaxMessageRetries() != null && functionConfig.getMaxMessageRetries() >= 0) {
throw new IllegalArgumentException("Message retries not yet supported in Go function");
}
}
private static void verifyNoTopicClash(Collection<String> inputTopics, String outputTopic)
throws IllegalArgumentException {
if (inputTopics.contains(outputTopic)) {
throw new IllegalArgumentException(
String.format(
"Output topic %s is also being used as an input topic (topics must be one or the other)",
outputTopic));
}
}
public static void doCommonChecks(FunctionConfig functionConfig) {
if (isEmpty(functionConfig.getTenant())) {
throw new IllegalArgumentException("Function tenant cannot be null");
}
if (isEmpty(functionConfig.getNamespace())) {
throw new IllegalArgumentException("Function namespace cannot be null");
}
if (isEmpty(functionConfig.getName())) {
throw new IllegalArgumentException("Function name cannot be null");
}
// go doesn't need className. Java className is done in doJavaChecks.
if (functionConfig.getRuntime() == FunctionConfig.Runtime.PYTHON) {
if (isEmpty(functionConfig.getClassName())) {
throw new IllegalArgumentException("Function classname cannot be null");
}
}
Collection<String> allInputTopics = collectAllInputTopics(functionConfig);
if (allInputTopics.isEmpty()) {
throw new IllegalArgumentException("No input topic(s) specified for the function");
}View on GitHub (pinned to 820761864e)
Solutions
- Set the tenant on the FunctionConfig before submitting, e.g. functionConfig.setTenant("public") (or pass --tenant to the CLI).
- If loading from YAML/JSON, add the missing 'tenant' key to the config file.
- Verify the field is populated after deserialization; empty-string tenants also fail, so trim/require a non-empty value.
- Use a tenant that exists in the cluster (commonly 'public') if you are unsure which one to use.
Example fix
// before
FunctionConfig config = new FunctionConfig();
config.setNamespace("default");
config.setName("my-fn");
// after
FunctionConfig config = new FunctionConfig();
config.setTenant("public");
config.setNamespace("default");
config.setName("my-fn"); Defensive patterns
Strategy: validation
Validate before calling
if (config == null || config.getTenant() == null || config.getTenant().trim().isEmpty()) {
throw new IllegalArgumentException("FunctionConfig.tenant must be set before submission");
} Type guard
static boolean hasTenant(FunctionConfig c) {
return c != null && c.getTenant() != null && !c.getTenant().trim().isEmpty();
} Try / catch
try {
FunctionConfigUtils.validateNonJavaFunction(functionConfig, null);
} catch (IllegalArgumentException e) {
log.error("Invalid function config: {}", e.getMessage());
// surface a friendly message asking for --tenant
} Prevention
- Always populate tenant/namespace/name as a set when building FunctionConfig objects.
- Use function config YAML templates that include all three identity fields.
- Run FunctionConfigUtils validation locally (or a dry-run) before submitting to the cluster.
- Prefer pulsar-admin CLI defaults (--tenant public) in scripts to avoid omissions.
When it happens
Trigger: Calling createFunction/updateFunction (via FunctionConfigUtils' createFunction paths, the functions worker REST API, or pulsar-admin functions create) with a FunctionConfig whose getTenant() returns null or the empty string; doCommonChecks is invoked from validateNonJavaFunction and validateJavaFunction.
Common situations: Building a FunctionConfig programmatically and forgetting setTenant(); YAML/JSON function config files that omit the 'tenant' key; CLI invocations missing the --tenant flag; configs deserialized from templates where tenant was left as a placeholder.
Understand the failure class
Background: "X is required", "field cannot be empty", error-the-field-is-required: missing required-field validation errors, explained — this error's family across 39 libraries.
Related errors
- When Guarantees == ATMOST_ONCE, autoAck must be equal to tru
- Function namespace cannot be null
- Function name cannot be null
- there are redundant configure for listener `${listenerName}`
- must not specify `${hostPort}` to different listener.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/a83051718aabb06b.
Report an issue: GitHub.