{"record":{"id":"7078026bea54b6fb","repo":"apache/pulsar","slug":"must-specify-function-source-or-sink-config","errorCode":null,"errorMessage":"Must specify Function, Source or Sink config","messagePattern":"Must specify Function, Source or Sink config","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/localrun/src/main/java/org/apache/pulsar/functions/LocalRunner.java","lineNumber":426,"sourceCode":"                        sinkConfig.getTransformFunctionClassName());\n                }\n\n                ClassLoader functionClassLoader = null;\n                ValidatableFunctionPackage validatableTransformFunction = null;\n                if (transformFunctionCodeClassLoader != null) {\n                    functionClassLoader = transformFunctionCodeClassLoader.getClassLoader() == null\n                        ? Thread.currentThread().getContextClassLoader()\n                        : transformFunctionCodeClassLoader.getClassLoader();\n                    validatableTransformFunction =\n                            new LoadedFunctionPackage(functionClassLoader, FunctionDefinition.class);\n                }\n\n                functionDetails = SinkConfigUtils.convert(\n                    sinkConfig,\n                    SinkConfigUtils.validateAndExtractDetails(sinkConfig, validatableFunctionPackage,\n                        validatableTransformFunction, true));\n            } else {\n                throw new IllegalArgumentException(\"Must specify Function, Source or Sink config\");\n            }\n\n            if (System.getProperty(FunctionCacheEntry.JAVA_INSTANCE_JAR_PROPERTY) == null) {\n                System.setProperty(FunctionCacheEntry.JAVA_INSTANCE_JAR_PROPERTY,\n                        LocalRunner.class.getProtectionDomain().getCodeSource().getLocation().getFile());\n            }\n\n            AuthenticationConfig authConfig = AuthenticationConfig.builder().clientAuthenticationPlugin\n                    (clientAuthPlugin)\n                    .clientAuthenticationParameters(clientAuthParams).useTls(useTls)\n                    .tlsAllowInsecureConnection(tlsAllowInsecureConnection)\n                    .tlsHostnameVerificationEnable(tlsHostNameVerificationEnabled)\n                    .tlsTrustCertsFilePath(tlsTrustCertFilePath).build();\n\n            String serviceUrl = DEFAULT_SERVICE_URL;\n            if (brokerServiceUrl != null) {\n                serviceUrl = brokerServiceUrl;\n            }","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/localrun/src/main/java/org/apache/pulsar/functions/LocalRunner.java#L408-L444","documentation":"LocalRunner requires exactly one of functionConfig, sourceConfig, or sinkConfig to be set, since it must build FunctionDetails from one of them. If none is configured it throws IllegalArgumentException with this message. This is a configuration-validation failure raised during start().","triggerScenarios":"Starting LocalRunner without calling setFunctionConfig/setSourceConfig/setSinkConfig, or after all three configs were explicitly cleared/reset to null.","commonSituations":"Programmatic runner construction missing the config step; config object built conditionally and left null; copying example code that used builder methods you omitted.","solutions":["Call one of setFunctionConfig, setSourceConfig, or setSinkConfig on LocalRunner before start()","Verify the config field is not overwritten to null by later builder/negative code paths","If configs are optional in your code, assert one is present before start"],"exampleFix":"// before\nLocalRunner runner = new LocalRunner();\nrunner.start(true);\n// after\nFunctionConfig functionConfig = new FunctionConfig();\nfunctionConfig.setClassName(\"org.example.MyFunction\");\nfunctionConfig.setInputs(Collections.singletonList(\"input-topic\"));\nfunctionConfig.setOutput(\"output-topic\");\nrunner.setFunctionConfig(functionConfig);\nrunner.start(true);","handlingStrategy":"validation","validationCode":"if (runner.getFunctionConfig() == null && runner.getSourceConfig() == null\n        && runner.getSinkConfig() == null) {\n    throw new IllegalStateException(\"Set functionConfig, sourceConfig, or sinkConfig before start\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    runner.start(true);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Must specify Function, Source or Sink config\")) {\n        // attach a config and restart with a fresh runner\n    }\n}","preventionTips":["Always set exactly one of function/source/sink config before start","Assert config presence in setup code","Build runners via a helper that enforces the config requirement"],"tags":["configuration","validation","illegal-argument"],"backgroundTag":"missing-required-config","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"}