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

  1. Set the output topic to a fully qualified name: persistent://<tenant>/<namespace>/<topic>
  2. Remove or blank the output field if the function does not produce output (empty output is allowed)
  3. Check for unsubstituted placeholders or whitespace in YAML/env-derived config
  4. 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

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


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