{"record":{"id":"dcec6feafabe77a8","repo":"apache/pulsar","slug":"batchsourceconfig-does-not-specify-discovery-trigg","errorCode":null,"errorMessage":"BatchSourceConfig does not specify Discovery Trigger ClassName","messagePattern":"BatchSourceConfig does not specify Discovery Trigger ClassName","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java","lineNumber":448,"sourceCode":"            mergedConfig.setCustomRuntimeOptions(newConfig.getCustomRuntimeOptions());\n        }\n        if (isBatchSource(existingConfig) != isBatchSource(newConfig)) {\n            throw new IllegalArgumentException(\"Sources cannot be update between regular sources and batchsource\");\n        }\n        if (newConfig.getBatchSourceConfig() != null) {\n            validateBatchSourceConfigUpdate(existingConfig.getBatchSourceConfig(), newConfig.getBatchSourceConfig());\n            mergedConfig.setBatchSourceConfig(newConfig.getBatchSourceConfig());\n        }\n        if (newConfig.getProducerConfig() != null) {\n            mergedConfig.setProducerConfig(newConfig.getProducerConfig());\n        }\n        return mergedConfig;\n    }\n\n    public static void validateBatchSourceConfig(BatchSourceConfig batchSourceConfig) throws IllegalArgumentException {\n        if (isEmpty(batchSourceConfig.getDiscoveryTriggererClassName())) {\n            log.error(\"BatchSourceConfig does not specify Discovery Trigger ClassName\");\n            throw new IllegalArgumentException(\"BatchSourceConfig does not specify Discovery Trigger ClassName\");\n        }\n    }\n\n    public static Map<String, Object> extractSourceConfig(SourceSpec sourceSpec, String fqfn) {\n        if (!StringUtils.isEmpty(sourceSpec.getConfigs())) {\n            TypeReference<HashMap<String, Object>> typeRef =\n                    new TypeReference<HashMap<String, Object>>() {\n            };\n            try {\n                return ObjectMapperFactory.getMapper().reader().forType(typeRef).readValue(sourceSpec.getConfigs());\n            } catch (IOException e) {\n                log.error().attr(\"source\", fqfn).exception(e)\n                        .log(\"Failed to read configs for source\");\n                throw new RuntimeException(e);\n            }\n        } else {\n            return null;\n        }","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java#L430-L466","documentation":"A BatchSourceConfig must name the class that triggers/discoveres batches (discoveryTriggererClassName). validateBatchSourceConfig logs and throws when that field is empty or null, since the batch source has no way to discover records without it.","triggerScenarios":"validateBatchSourceConfig (invoked from validateAndExtractDetails when batchSourceConfig is present) finds batchSourceConfig.getDiscoveryTriggererClassName() empty/null.","commonSituations":"batchSourceConfig JSON contains only batchSize or discoveryTriggererConfig but omits discoveryTriggererClassName; typo in the key name; the triggerer class field cleared during config editing.","solutions":["Set discoveryTriggererClassName to the fully qualified class implementing DiscoveryTriggerer in the batchSourceConfig","Confirm the triggerer class is packaged in the uploaded archive","Fix JSON key spelling so the field deserializes correctly"],"exampleFix":"// before\n\"batchSourceConfig\":{\"batchSize\":10}\n// after\n\"batchSourceConfig\":{\"discoveryTriggererClassName\":\"org.apache.pulsar.functions.source.batch.builder.PulsarRecordGenerator\",\"batchSize\":10}","handlingStrategy":"validation","validationCode":"if (config.getBatchSourceConfig() != null\n    && (config.getBatchSourceConfig().getDiscoveryTriggererClassName() == null\n        || config.getBatchSourceConfig().getDiscoveryTriggererClassName().isEmpty())) {\n    throw new IllegalArgumentException(\"discoveryTriggererClassName is required in batchSourceConfig\");\n}","typeGuard":null,"tryCatchPattern":"try { validateAndExtractDetails(...); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"Discovery Trigger ClassName\")) { /* set discoveryTriggererClassName and resubmit */ } else { throw e; } }","preventionTips":["Validate batchSourceConfig JSON against a schema with required discoveryTriggererClassName","Keep the triggerer class packaged with the connector archive","Copy known-good batchSourceConfig examples rather than hand-writing them"],"tags":["pulsar-functions","batch-source","config-validation"],"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"}