{"record":{"id":"a11d384b6cc34e2c","repo":"apache/pulsar","slug":"logtopic-topic-s-is-invalid","errorCode":null,"errorMessage":"LogTopic topic %s is invalid","messagePattern":"LogTopic topic (.+?) is invalid","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":825,"sourceCode":"        if (allInputTopics.isEmpty()) {\n            throw new IllegalArgumentException(\"No input topic(s) specified for the function\");\n        }\n        for (String topic : allInputTopics) {\n            if (!TopicName.isValid(topic)) {\n                throw new IllegalArgumentException(String.format(\"Input topic %s is invalid\", topic));\n            }\n        }\n\n        if (!isEmpty(functionConfig.getOutput())) {\n            if (!TopicName.isValid(functionConfig.getOutput())) {\n                throw new IllegalArgumentException(\n                        String.format(\"Output topic %s is invalid\", functionConfig.getOutput()));\n            }\n        }\n\n        if (!isEmpty(functionConfig.getLogTopic())) {\n            if (!TopicName.isValid(functionConfig.getLogTopic())) {\n                throw new IllegalArgumentException(\n                        String.format(\"LogTopic topic %s is invalid\", functionConfig.getLogTopic()));\n            }\n        }\n\n        if (!isEmpty(functionConfig.getDeadLetterTopic())) {\n            if (!TopicName.isValid(functionConfig.getDeadLetterTopic())) {\n                throw new IllegalArgumentException(\n                        String.format(\"DeadLetter topic %s is invalid\", functionConfig.getDeadLetterTopic()));\n            }\n        }\n\n        if (functionConfig.getParallelism() != null && functionConfig.getParallelism() <= 0) {\n            throw new IllegalArgumentException(\"Function parallelism must be a positive number\");\n        }\n        // Ensure that topics aren't being used as both input and output\n        verifyNoTopicClash(allInputTopics, functionConfig.getOutput());\n\n        WindowConfig windowConfig = functionConfig.getWindowConfig();","sourceCodeStart":807,"sourceCodeEnd":843,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L807-L843","documentation":"When a function's log topic is set, doCommonChecks requires it to be a valid Pulsar topic name; otherwise the function is rejected with this IllegalArgumentException. The log topic receives all log messages produced by the function's log() calls, so it must be addressable by the Pulsar client.","triggerScenarios":"createFunction/updateFunction with functionConfig.getLogTopic() non-empty and TopicName.isValid(logTopic) false: e.g. 'logs' bare name, 'persistent://tenant/ns/' with empty topic segment, or whitespace-padded string from YAML.","commonSituations":"Enabling function logging via CLI (--log-topic) with a shorthand name, copying the field from another cluster config with different defaults, YAML indentation issues yielding malformed strings.","solutions":["Use a fully qualified topic: persistent://public/default/function-logs","Clear the log-topic field if log collection is not needed","Ensure the tenant/namespace in the log topic exists in the target cluster","Trim the value and re-validate with TopicName.isValid before submit"],"exampleFix":"// before\nconfig.setLogTopic(\"fn-logs\");\n// after\nconfig.setLogTopic(\"persistent://public/default/fn-logs\");","handlingStrategy":"validation","validationCode":"String logTopic = config.getLogTopic();\nif (logTopic != null && !logTopic.isEmpty() && !TopicName.isValid(logTopic.trim())) {\n    throw new IllegalArgumentException(\"Invalid log topic: \" + logTopic);\n}","typeGuard":"boolean hasValidLogTopic(FunctionConfig c) {\n    String t = c.getLogTopic();\n    return t == null || t.isEmpty() || TopicName.isValid(t.trim());\n}","tryCatchPattern":"try {\n    admin.functions().createFunction(functionConfig, sourceConfigLocation);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"LogTopic\")) {\n        // correct config.getLogTopic() or drop it\n    }\n    throw e;\n}","preventionTips":["Omit log-topic unless you actively collect function logs into Pulsar","Use the same tenant/ns as the function with a dedicated topic name","Validate all three topics (input/output/log) together before submit","Beware YAML string indentation producing stray characters"],"tags":["pulsar-functions","validation","topic-name","logging"],"backgroundTag":"invalid-topic-name","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"}