{"record":{"id":"f59e543abf9a5649","repo":"apache/pulsar","slug":"tenant-is-not-provided-f59e54","errorCode":null,"errorMessage":"Tenant is not provided","messagePattern":"Tenant is not provided","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"error","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java","lineNumber":91,"sourceCode":"        super(workerServiceSupplier, FunctionDetails.ComponentType.SINK);\n    }\n\n    @Override\n    public void registerSink(final String tenant,\n                             final String namespace,\n                             final String sinkName,\n                             final InputStream uploadedInputStream,\n                             final FormDataContentDisposition fileDetail,\n                             final String sinkPkgUrl,\n                             final SinkConfig sinkConfig,\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 (sinkName == null) {\n            throw new RestException(Response.Status.BAD_REQUEST, \"Sink name is not provided\");\n        }\n        if (sinkConfig == null) {\n            throw new RestException(Response.Status.BAD_REQUEST, \"Sink config is not provided\");\n        }\n\n        throwRestExceptionIfUnauthorizedForNamespace(tenant, namespace, sinkName, \"register\", authParams);\n\n        try {\n            // Check tenant exists\n            worker().getBrokerAdmin().tenants().getTenantInfo(tenant);\n\n            String qualifiedNamespace = tenant + \"/\" + namespace;","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java#L73-L109","documentation":"registerSink in SinksImpl validates its request parameters up front and throws a 400 Bad Request RestException when the tenant path/query parameter is null. Sink registration is namespaced under tenant/namespace, so a tenant must always be supplied. This fail-fast check happens before any authorization or cluster lookup.","triggerScenarios":"Calling the sink registration REST endpoint (registerSink) with tenant=null: omitting the tenant path parameter in the URL, or passing a null tenant when invoking SinksImpl programmatically.","commonSituations":"Building the REST URL with a templating helper that drops empty path segments; CLI/script variable for tenant left empty; client SDK binding that maps missing query params to null instead of rejecting them.","solutions":["Include the tenant in the request URL: PUT /admin/v3/sinks/{tenant}/{namespace}/{sinkName} with all three segments populated.","Check the client code or script variable that supplies tenant and ensure it is a non-empty string before the call.","If invoking SinksImpl directly, guard the tenant argument for null/blank before calling registerSink."],"exampleFix":"// before\nString url = String.format(\"/admin/v3/sinks/%s/%s/%s\", tenant, namespace, sinkName); // tenant == null\n// after\nif (tenant == null || tenant.isBlank()) {\n    throw new IllegalArgumentException(\"tenant is required\");\n}\nString url = String.format(\"/admin/v3/sinks/%s/%s/%s\", tenant, namespace, sinkName);","handlingStrategy":"validation","validationCode":"if (tenant == null || tenant.isBlank()) {\n    throw new IllegalArgumentException(\"tenant must be provided\");\n}","typeGuard":"boolean hasTenant(String tenant) {\n    return tenant != null && !tenant.isBlank();\n}","tryCatchPattern":"try {\n    sinks.registerSink(tenant, ns, name, cfg, null, null, null, authParams);\n} catch (RestException e) {\n    if (e.getResponse().getStatus() == 400 && \"Tenant is not provided\".equals(e.getMessage())) {\n        // supply tenant and re-issue the request\n    } else { throw e; }\n}","preventionTips":["Build REST URLs from a single helper that asserts all path segments are non-blank","Fail fast in scripts on empty environment variables feeding tenant/namespace","Keep tenant/namespace/name in one config record validated at startup"],"tags":["rest-api","bad-request","validation","pulsar-sinks"],"backgroundTag":"missing-required-parameter","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"}