{"record":{"id":"0469fbd1d227c065","repo":"apache/pulsar","slug":"source-config-is-not-provided","errorCode":null,"errorMessage":"Source config is not provided","messagePattern":"Source config is not provided","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"warning","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java","lineNumber":99,"sourceCode":"                               final String sourcePkgUrl,\n                               final SourceConfig sourceConfig,\n                               final AuthenticationParameters authParams) {\n\n        if (!isWorkerServiceAvailable()) {\n            throwUnavailableException();\n        }\n\n        if (tenant == null) {\n            throw new RestException(Response.Status.BAD_REQUEST, \"Tenant is not provided\");\n        }\n        if (namespace == null) {\n            throw new RestException(Response.Status.BAD_REQUEST, \"Namespace is not provided\");\n        }\n        if (sourceName == null) {\n            throw new RestException(Response.Status.BAD_REQUEST, \"Source name is not provided\");\n        }\n        if (sourceConfig == null) {\n            throw new RestException(Response.Status.BAD_REQUEST, \"Source config is not provided\");\n        }\n\n        throwRestExceptionIfUnauthorizedForNamespace(tenant, namespace, sourceName, \"register\", authParams);\n\n        try {\n            // Check tenant exists\n            worker().getBrokerAdmin().tenants().getTenantInfo(tenant);\n\n            String qualifiedNamespace = tenant + \"/\" + namespace;\n            List<String> namespaces = worker().getBrokerAdmin().namespaces().getNamespaces(tenant);\n            if (namespaces != null && !namespaces.contains(qualifiedNamespace)) {\n                String qualifiedNamespaceWithCluster = String.format(\"%s/%s/%s\", tenant,\n                        worker().getWorkerConfig().getPulsarFunctionsCluster(), namespace);\n                if (namespaces != null && !namespaces.contains(qualifiedNamespaceWithCluster)) {\n                    log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sourceName)\n\n                            .attr(\"namespace3\", namespace).log(\"/ / Namespace does not exist\");\n                    throw new RestException(Response.Status.BAD_REQUEST, \"Namespace does not exist\");","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java#L81-L117","documentation":"registerSource requires a SourceConfig body. If sourceConfig is null after the name checks, it returns HTTP 400 'Source config is not provided'. The config carries topicName, className, serialization class, etc., so it is mandatory.","triggerScenarios":"POST to the source endpoint without a JSON SourceConfig body, with a wrong Content-Type so the body failed to bind, or programmatic createSource calls passing null config.","commonSituations":"curl calls omitting -d/--data or the @file argument; sending the config as a query param instead of the request body; SDK wrapper dropping the config object; misconfigured Content-Type (text/plain instead of application/json).","solutions":["Include a valid SourceConfig JSON body with the request and set Content-Type: application/json.","Verify minimal required fields: className, topicName (or topicsPattern), and serialization configs.","In programmatic use, construct and pass a non-null SourceConfig instance."],"exampleFix":"// before\ncurl -X POST .../sources/t/n/s   // no body -> 400\n// after\ncurl -X POST -H 'Content-Type: application/json' -d @sourceConfig.yaml.json .../sources/t/n/s","handlingStrategy":"validation","validationCode":"if (sourceConfig == null) throw new IllegalArgumentException(\"SourceConfig body is required\");\n// and for REST: always send Content-Type: application/json with a non-empty body","typeGuard":"boolean hasRequiredSourceConfig(SourceConfig c) { return c != null && c.getClassName() != null && c.getTopicName() != null; }","tryCatchPattern":"try { admin.sources().createSource(tenant, ns, name, file, cfg); } catch (PulsarAdminException e) { if (e.getStatusCode() == 400) { /* inspect message, fix body */ } throw e; }","preventionTips":["Always send the SourceConfig JSON body with Content-Type: application/json","Validate config YAML/JSON with the CLI before submitting via REST","Require className and topicName in your config templates","Never pass the config as a query parameter"],"tags":["validation","http-400","rest-api","request-body"],"backgroundTag":"missing-request-body","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}