{"record":{"id":"6bfd754943c23ac4","repo":"apache/pulsar","slug":"source-namespace-cannot-be-null","errorCode":null,"errorMessage":"Source namespace cannot be null","messagePattern":"Source namespace cannot be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java","lineNumber":269,"sourceCode":"        if (!isEmpty(functionDetails.getRuntimeFlags())) {\n            sourceConfig.setRuntimeFlags(functionDetails.getRuntimeFlags());\n        }\n\n        if (!isEmpty(functionDetails.getCustomRuntimeOptions())) {\n            sourceConfig.setCustomRuntimeOptions(functionDetails.getCustomRuntimeOptions());\n        }\n\n        return sourceConfig;\n    }\n\n    public static ExtractedSourceDetails validateAndExtractDetails(SourceConfig sourceConfig,\n                                                                   ValidatableFunctionPackage sourceFunction,\n                                                                   boolean validateConnectorConfig) {\n        if (isEmpty(sourceConfig.getTenant())) {\n            throw new IllegalArgumentException(\"Source tenant cannot be null\");\n        }\n        if (isEmpty(sourceConfig.getNamespace())) {\n            throw new IllegalArgumentException(\"Source namespace cannot be null\");\n        }\n        if (isEmpty(sourceConfig.getName())) {\n            throw new IllegalArgumentException(\"Source name cannot be null\");\n        }\n        if (!isEmpty(sourceConfig.getTopicName()) && !TopicName.isValid(sourceConfig.getTopicName())) {\n            throw new IllegalArgumentException(\"Topic name is invalid\");\n        }\n        if (!isEmpty(sourceConfig.getLogTopic())) {\n            if (!TopicName.isValid(sourceConfig.getLogTopic())) {\n                throw new IllegalArgumentException(\n                        String.format(\"LogTopic topic %s is invalid\", sourceConfig.getLogTopic()));\n            }\n        }\n        if (sourceConfig.getParallelism() != null && sourceConfig.getParallelism() <= 0) {\n            throw new IllegalArgumentException(\"Source parallelism must be a positive number\");\n        }\n        if (sourceConfig.getResources() != null) {\n            ResourceConfigUtils.validate(sourceConfig.getResources());","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java#L251-L287","documentation":"validateAndExtractDetails requires SourceConfig.namespace to be non-null and non-empty because the source's fully-qualified identity is tenant/namespace/name. After the tenant check passes, a null/empty namespace aborts validation with this IllegalArgumentException.","triggerScenarios":"Calling source registration/validation with a SourceConfig that has tenant set but namespace null or empty — e.g. pulsar-admin sources create with a config file missing the 'namespace' field, or programmatic construction omitting setNamespace().","commonSituations":"Hand-written source config YAML missing the namespace key; code that sets tenant and name but not namespace; migrating configs between tools where one defaults the namespace and Pulsar does not.","solutions":["Set the namespace on the SourceConfig, e.g. sourceConfig.setNamespace(\"default\")","If configs come from a file/template, add the missing 'namespace' entry and reload","Pre-validate in your own tooling: fail early with a clear message if namespace is blank before invoking Pulsar APIs"],"exampleFix":"// before\nSourceConfig cfg = new SourceConfig();\ncfg.setTenant(\"public\");\ncfg.setName(\"my-source\");\n// after\nSourceConfig cfg = new SourceConfig();\ncfg.setTenant(\"public\");\ncfg.setNamespace(\"default\");\ncfg.setName(\"my-source\");","handlingStrategy":"validation","validationCode":"if (cfg.getNamespace() == null || cfg.getNamespace().isEmpty()) {\n    throw new IllegalArgumentException(\"sourceConfig.namespace must be set (use 'default' if unsure)\");\n}","typeGuard":"static boolean hasNamespace(SourceConfig cfg) {\n    return cfg != null && cfg.getNamespace() != null && !cfg.getNamespace().trim().isEmpty();\n}","tryCatchPattern":"try {\n    SourceConfigUtils.validateAndExtractDetails(cfg, pkg, true);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Source namespace cannot be null\")) {\n        // reject submission with a message asking for --namespace\n    }\n}","preventionTips":["Use a helper that builds SourceConfig with tenant, namespace and name always set","Add the namespace to config templates and CI lint checks for source YAML","When copying configs between environments, diff required fields before submit"],"tags":["pulsar-functions","config-validation","illegal-argument"],"backgroundTag":"missing-required-config-field","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"}