{"record":{"id":"4d377d55a1fac7ad","repo":"apache/pulsar","slug":"client-is-not-authorized-to-perform-operation-4d377d","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/SourcesImpl.java","lineNumber":126,"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\", sourceName)\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\", sourceName)\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\", sourceName)\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\", sourceName)\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, sourceName)) {\n            log.error().attr(\"componentType\", ComponentTypeUtils.toString(componentType)).attr(\"tenant\", tenant)\n\n                    .attr(\"namespace\", namespace).attr(\"componentName\", sourceName).log(\"/ / already exists\");","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java#L108-L144","documentation":"This error is thrown by the Functions Worker REST API when the underlying Pulsar admin client receives a PulsarAdminException.NotAuthorizedException while checking tenant/namespace permissions during source registration. The worker converts it into HTTP 401 UNAUTHORIZED, meaning the authenticated client lacks permissions to operate on the target tenant, not a malformed request.","triggerScenarios":"Calling the registerSource REST endpoint (POST to the functions/sources API) when the client's role does not have produce/consume/admin permissions on the tenant or namespace hosting the source.","commonSituations":"Client configured with a role that lacks permissions in authorization.conf or the Pulsar permissions API; using the wrong tenant name; expired or misconfigured auth tokens/plugin in the client; broker authorization enabled but worker not forwarding client credentials.","solutions":["Grant the client role permissions on the tenant/namespace: pulsar-admin namespaces grant-permissions <tenant>/<ns> --role <role> --actions produce,consume,functions","Verify the client's auth credentials (auth plugin and parameters) are valid and identify the intended role","Check broker authorizationProvider config and brokerClientAuthenticationPlugin on the worker so credentials are forwarded correctly","Confirm you are targeting the correct tenant; a wrong tenant the role lacks rights on also yields 401"],"exampleFix":"// before (client without permissions)\npulsar-admin sources create --tenant public --namespace default ... // -> 401\n// after\npulsar-admin namespaces grant-permissions public/default --role my-role --actions produce,consume\npulsar-admin sources create --tenant public --namespace default ... // -> success","handlingStrategy":"try-catch","validationCode":"// check role permissions before registering\ntry (PulsarAdmin admin = PulsarAdminClient.builder().serviceHttpUrl(adminUrl)\n        .authentication(AuthenticationFactory.token(token)).build()) {\n    Set<String> perms = admin.namespaces().getPermissions(\"public/default\");\n    if (perms == null || !perms.contains(\"functions\")) {\n        throw new IllegalStateException(\"role lacks functions permission on public/default\");\n    }\n}","typeGuard":"boolean isAuthorized(Set<String> perms) {\n    return perms != null && (perms.contains(\"functions\") || perms.contains(\"admin\"));\n}","tryCatchPattern":"try {\n    sources.createSource(sourceConfig, pkgUrl, inputStream);\n} catch (PulsarAdminException.NotAuthorizedException | javax.ws.rs.ClientErrorException e) {\n    if (((ClientErrorException) e).getResponse().getStatus() == 401) {\n        log.error(\"Not authorized for tenant {} — check role permissions\", sourceConfig.getTenant(), e);\n    } else { throw e; }\n}","preventionTips":["Provision role permissions (grant-permissions with functions/admin actions) as part of environment bootstrap","Use the same role for tenant admin and source deployment in CI","Verify auth plugin/token config on the client and that the worker forwards credentials","Pin tenant/namespace names in one shared config to avoid targeting unknown tenants"],"tags":["authorization","rest-api","pulsar-functions","permissions"],"backgroundTag":"client-not-authorized","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"}