{"record":{"id":"022360f7acde8306","repo":"apache/pulsar","slug":"client-is-not-authorized-to-perform-operation-022360","errorCode":null,"errorMessage":"Client is not authorized to perform operation","messagePattern":"Client is not authorized to perform operation","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"error","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java","lineNumber":127,"sourceCode":"            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\", sinkName)\n\n                            .attr(\"namespace3\", namespace).log(\"/ / Namespace does not exist\");\n                    throw new RestException(Response.Status.BAD_REQUEST, \"Namespace does not exist\");\n                }\n            }\n        } catch (PulsarAdminException.NotAuthorizedException e) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sinkName)\n\n                    .attr(\"componentType\", ComponentTypeUtils.toString(componentType))\n\n                    .log(\"/ / Client is not authorized to operate on tenant\");\n            throw new RestException(Response.Status.UNAUTHORIZED, \"Client is not authorized to perform operation\");\n        } catch (PulsarAdminException.NotFoundException e) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sinkName)\n\n                    .attr(\"tenant3\", tenant).log(\"/ / Tenant does not exist\");\n            throw new RestException(Response.Status.BAD_REQUEST, \"Tenant does not exist\");\n        } catch (PulsarAdminException e) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sinkName)\n\n                    .exception(e).log(\"/ / Issues getting tenant data\");\n            throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());\n        }\n\n        FunctionMetaDataManager functionMetaDataManager = worker().getFunctionMetaDataManager();\n\n        if (functionMetaDataManager.containsFunction(tenant, namespace, sinkName)) {\n            log.error().attr(\"componentType\", ComponentTypeUtils.toString(componentType)).attr(\"tenant\", tenant)\n\n                    .attr(\"namespace\", namespace).attr(\"componentName\", sinkName).log(\"/ / already exists\");","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java#L109-L145","documentation":"registerSink catches PulsarAdminException.NotAuthorizedException raised while inspecting the tenant/namespace (getting tenant data or listing namespaces) and rethrows it as a 401 UNAUTHORIZED RestException with this generic message. It means the worker's admin client credentials are not authorized for the target tenant/namespace policies, not necessarily the end user's credentials.","triggerScenarios":"registerSink where the worker's PulsarAdmin session lacks admin/tenant permissions: the worker's principal is not listed in the tenant adminRoles, namespace policies deny the role, or authorization is enabled and the worker role has no functions/sinks permissions on the namespace.","commonSituations":"Kubernetes deployments where the worker's auth token role was never granted on the tenant; enabling authorization on an existing cluster without updating tenant admin roles; wrong token/key file mounted for the functions worker.","solutions":["Grant the worker's role tenant admin rights: pulsar-admin tenants update tenant --admin-roles <worker-role>.","Check namespace policies: pulsar-admin namespaces grant-permission tenant/ns --actions functions,sinks --role <worker-role>.","Verify the worker's authentication plugin/parameters and that its token maps to the intended role.","Inspect broker authorization logs to see which role/action was denied."],"exampleFix":"// before: worker role not authorized\ntenants.update(tenant, new TenantInfoImpl(Collections.emptySet(), Collections.emptySet()));\n// after: include the worker role as tenant admin\npulsar-admin tenants update my-tenant --admin-roles functions-worker-role","handlingStrategy":"try-catch","validationCode":"// verify authorization up front\nadmin.tenants().getTenantInfo(tenant); // throws NotAuthorizedException if the worker role lacks access\nadmin.namespaces().getPermissions(tenant + \"/\" + namespace);","typeGuard":null,"tryCatchPattern":"try {\n    sinks.registerSink(tenant, ns, name, cfg, null, null, null, authParams);\n} catch (RestException e) {\n    if (e.getResponse().getStatus() == 401) {\n        // grant the worker role tenant admin / namespace functions+sinks permissions\n    } else { throw e; }\n}","preventionTips":["Add the functions worker role to every tenant's adminRoles at tenant creation time","Keep worker auth token/key provisioning in infrastructure-as-code","Test authorization by running an admin op as the worker role before deploying sinks"],"tags":["authorization","security","rest-api","pulsar-sinks"],"backgroundTag":"authorization-denied","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"}