{"record":{"id":"a9342d2c92c14515","repo":"apache/pulsar","slug":"function-name-cannot-be-null","errorCode":null,"errorMessage":"Function name cannot be null","messagePattern":"Function name cannot be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":797,"sourceCode":"    private static void verifyNoTopicClash(Collection<String> inputTopics, String outputTopic)\n            throws IllegalArgumentException {\n        if (inputTopics.contains(outputTopic)) {\n            throw new IllegalArgumentException(\n                    String.format(\n                            \"Output topic %s is also being used as an input topic (topics must be one or the other)\",\n                            outputTopic));\n        }\n    }\n\n    public static void doCommonChecks(FunctionConfig functionConfig) {\n        if (isEmpty(functionConfig.getTenant())) {\n            throw new IllegalArgumentException(\"Function tenant cannot be null\");\n        }\n        if (isEmpty(functionConfig.getNamespace())) {\n            throw new IllegalArgumentException(\"Function namespace cannot be null\");\n        }\n        if (isEmpty(functionConfig.getName())) {\n            throw new IllegalArgumentException(\"Function name cannot be null\");\n        }\n        // go doesn't need className. Java className is done in doJavaChecks.\n        if (functionConfig.getRuntime() == FunctionConfig.Runtime.PYTHON) {\n            if (isEmpty(functionConfig.getClassName())) {\n                throw new IllegalArgumentException(\"Function classname cannot be null\");\n            }\n        }\n\n        Collection<String> allInputTopics = collectAllInputTopics(functionConfig);\n        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","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L779-L815","documentation":"doCommonChecks requires a function name; together with tenant and namespace it forms the unique function identity (tenant/namespace/name). A null or empty name makes the function unaddressable, so validation throws this IllegalArgumentException immediately.","triggerScenarios":"Creating or updating a function with a FunctionConfig whose getName() is null/empty — via validateJavaFunction/validateNonJavaFunction, the functions worker REST API, or pulsar-admin functions create without --name or with a config file lacking the 'name' key.","commonSituations":"Programmatic config building where name was overlooked; YAML/JSON templates missing 'name'; dynamic generation of configs in loops where the name variable was never assigned; refactors renaming the setter that left the call site behind.","solutions":["Set a non-empty name: functionConfig.setName(\"my-function\").","Add the 'name' key to the YAML/JSON config file.","Check code paths that build configs dynamically to ensure the name variable is assigned before validation.","Remember the name must be valid within the tenant/namespace and not collide with an existing function."],"exampleFix":"// before\nconfig.setTenant(\"public\");\nconfig.setNamespace(\"default\");\n// after\nconfig.setTenant(\"public\");\nconfig.setNamespace(\"default\");\nconfig.setName(\"my-function\");","handlingStrategy":"validation","validationCode":"if (config == null || config.getName() == null || config.getName().trim().isEmpty()) {\n    throw new IllegalArgumentException(\"FunctionConfig.name must be set before submission\");\n}","typeGuard":"static boolean hasName(FunctionConfig c) {\n    return c != null && c.getName() != null && !c.getName().trim().isEmpty();\n}","tryCatchPattern":"try {\n    FunctionConfigUtils.validateNonJavaFunction(functionConfig, null);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"name\")) {\n        throw new IllegalStateException(\"Function name is required: pass --name or set 'name' in the config\", e);\n    }\n    throw e;\n}","preventionTips":["Derive the function name from a single required variable so it cannot be silently null.","In config generators, assert name is non-empty before writing the YAML/JSON.","Keep tenant/namespace/name assigned together in one factory method.","Check for name collisions within the tenant/namespace before create."],"tags":["pulsar","functions","configuration","validation"],"backgroundTag":"required-field-missing","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}