apache/pulsar · error · IllegalArgumentException
Output topic %s is invalid
Error message
Output topic %s is invalid
What it means
FunctionConfigUtils.doCommonChecks validates the function's output topic with TopicName.isValid(). If the output field is non-empty but not a syntactically valid Pulsar topic name, creation fails with this IllegalArgumentException. This keeps the function from being deployed against a topic it could never publish to.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:818
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");
}
for (String topic : allInputTopics) {
if (!TopicName.isValid(topic)) {
throw new IllegalArgumentException(String.format("Input topic %s is invalid", topic));
}
}
if (!isEmpty(functionConfig.getOutput())) {
if (!TopicName.isValid(functionConfig.getOutput())) {
throw new IllegalArgumentException(
String.format("Output topic %s is invalid", functionConfig.getOutput()));
}
}
if (!isEmpty(functionConfig.getLogTopic())) {
if (!TopicName.isValid(functionConfig.getLogTopic())) {
throw new IllegalArgumentException(
String.format("LogTopic topic %s is invalid", functionConfig.getLogTopic()));
}
}
if (!isEmpty(functionConfig.getDeadLetterTopic())) {
if (!TopicName.isValid(functionConfig.getDeadLetterTopic())) {
throw new IllegalArgumentException(
String.format("DeadLetter topic %s is invalid", functionConfig.getDeadLetterTopic()));
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Set the output topic to a fully qualified name: persistent://<tenant>/<namespace>/<topic>
- Remove or blank the output field if the function does not produce output (empty output is allowed)
- Check for unsubstituted placeholders or whitespace in YAML/env-derived config
- Validate locally with TopicName.isValid(output) before calling the admin API
Example fix
// before
config.setOutput("results-topic");
// after
config.setOutput("persistent://public/default/results-topic"); Defensive patterns
Strategy: validation
Validate before calling
if (config.getOutput() != null && !config.getOutput().isEmpty()
&& !TopicName.isValid(config.getOutput().trim())) {
throw new IllegalArgumentException("Invalid output topic: " + config.getOutput());
} Type guard
boolean validOptionalTopic(String t) {
return t == null || t.isEmpty() || TopicName.isValid(t.trim());
} Try / catch
try {
admin.functions().updateFunction(functionConfig, configLocation);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Output topic")) {
// fix functionConfig.getOutput() to persistent://tenant/ns/topic
}
throw e;
} Prevention
- Verify output topic exists/valid via admin top API before creating the function
- Keep output names fully qualified; avoid shorthand
- Scan manifests for unsubstituted placeholders like ${OUTPUT_TOPIC}
- Trim values derived from env vars
When it happens
Trigger: Submitting a FunctionConfig via createFunction/updateFunction (CLI, REST admin API) where functionConfig.getOutput() is non-empty and fails TopicName.isValid: e.g. 'my-output' without tenant/namespace when no defaults apply, malformed persistent:// URI, or stray whitespace.
Common situations: Typos in the sink/output topic, mixing up the dead-letter and output fields, partial topic names after refactoring tenants/namespaces, template placeholders like ${OUTPUT_TOPIC} left unsubstituted in YAML.
Related errors
- Input topic %s is invalid
- testTopic can not be blank
- Invalid short topic name '%s', it should be in the format of
- Invalid topic name: %s
- Function config is not provided
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/542ff054f4d15211.
Report an issue: GitHub.