{"record":{"id":"c5262032c8e63726","repo":"apache/pulsar","slug":"messagepayloadprocessor-class-name-required","errorCode":null,"errorMessage":"MessagePayloadProcessor class name required","messagePattern":"MessagePayloadProcessor class name required","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":929,"sourceCode":"                throw new IllegalArgumentException(\"The supplied go file does not exist\");\n            }\n        }\n\n        if (functionConfig.getInputSpecs() != null) {\n            functionConfig.getInputSpecs().forEach((topicName, conf) -> {\n                // receiver queue size should be >= 0\n                if (conf.getReceiverQueueSize() != null && conf.getReceiverQueueSize() < 0) {\n                    throw new IllegalArgumentException(\n                        \"Receiver queue size should be >= zero\");\n                }\n\n                if (conf.getCryptoConfig() != null && isBlank(conf.getCryptoConfig().getCryptoKeyReaderClassName())) {\n                    throw new IllegalArgumentException(\n                            \"CryptoKeyReader class name required\");\n                }\n                if (conf.getMessagePayloadProcessorConfig() != null && isBlank(\n                        conf.getMessagePayloadProcessorConfig().getClassName())) {\n                    throw new IllegalArgumentException(\n                            \"MessagePayloadProcessor class name required\");\n                }\n            });\n        }\n\n        if (functionConfig.getProducerConfig() != null\n                && functionConfig.getProducerConfig().getCryptoConfig() != null) {\n            if (isBlank(functionConfig.getProducerConfig().getCryptoConfig().getCryptoKeyReaderClassName())) {\n                throw new IllegalArgumentException(\"CryptoKeyReader class name required\");\n            }\n\n            if (functionConfig.getProducerConfig().getCryptoConfig().getEncryptionKeys() == null\n                    || functionConfig.getProducerConfig().getCryptoConfig().getEncryptionKeys().length == 0) {\n                throw new IllegalArgumentException(\"Must provide encryption key name for crypto key reader\");\n            }\n        }\n    }\n","sourceCodeStart":911,"sourceCodeEnd":947,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L911-L947","documentation":"When an InputSpec defines a MessagePayloadProcessorConfig, its className must be a non-blank string identifying the payload processor implementation. A null/empty class name leaves the processor unresolvable, so validation throws IllegalArgumentException('MessagePayloadProcessor class name required').","triggerScenarios":"Setting InputSpec.setMessagePayloadProcessorConfig(new MessagePayloadProcessorConfig()) or one whose getClassName() is empty/whitespace, then validating the function config (create/update path).","commonSituations":"Constructing the processor config object without filling in the class name; YAML/JSON payload-processor block present but className key missing; placeholder like '${processorClass}' unresolved; copy of sample config where className line was deleted.","solutions":["Set the fully qualified implementation class name: messagePayloadProcessorConfig.setClassName(\"com.example.MyPayloadProcessor\")","Ensure the processor class is packaged and loadable by the function worker","If payload processing is not required for that topic, remove the MessagePayloadProcessorConfig from the InputSpec","Verify the config file/templating actually populates the className field"],"exampleFix":"// before\nMessagePayloadProcessorConfig ppc = new MessagePayloadProcessorConfig();\ninputSpec.setMessagePayloadProcessorConfig(ppc); // className null\n// after\nMessagePayloadProcessorConfig ppc = new MessagePayloadProcessorConfig();\nppc.setClassName(\"com.example.MyPayloadProcessor\");\ninputSpec.setMessagePayloadProcessorConfig(ppc);","handlingStrategy":"validation","validationCode":"MessagePayloadProcessorConfig ppc = spec.getMessagePayloadProcessorConfig();\nif (ppc != null && (ppc.getClassName() == null || ppc.getClassName().isBlank())) {\n    throw new IllegalStateException(\"MessagePayloadProcessor className required\");\n}","typeGuard":"boolean hasPayloadProcessorClass(MessagePayloadProcessorConfig c) {\n    return c == null || (c.getClassName() != null && !c.getClassName().isBlank());\n}","tryCatchPattern":"try {\n    admin.functions().createFunction(conf);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"MessagePayloadProcessor class name\")) {\n        spec.getMessagePayloadProcessorConfig().setClassName(DEFAULT_PROCESSOR_CLASS);\n        admin.functions().createFunction(conf);\n    } else throw e;\n}","preventionTips":["Use a builder/factory that requires className in its constructor so it cannot be blank","Verify the className against the classes actually packaged in your function nar/jar","Fail config parsing when template placeholders like ${...} remain unexpanded"],"tags":["pulsar-functions","config-validation"],"backgroundTag":"missing-required-class-name","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"}