apache/pulsar · error · RestException

Client is not authorized to perform operation

Error message

Client is not authorized to perform operation

What it means

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.

Source

Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java:127

            String qualifiedNamespace = tenant + "/" + namespace;
            List<String> namespaces = worker().getBrokerAdmin().namespaces().getNamespaces(tenant);
            if (namespaces != null && !namespaces.contains(qualifiedNamespace)) {
                String qualifiedNamespaceWithCluster = String.format("%s/%s/%s", tenant,
                        worker().getWorkerConfig().getPulsarFunctionsCluster(), namespace);
                if (namespaces != null && !namespaces.contains(qualifiedNamespaceWithCluster)) {
                    log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sinkName)

                            .attr("namespace3", namespace).log("/ / Namespace does not exist");
                    throw new RestException(Response.Status.BAD_REQUEST, "Namespace does not exist");
                }
            }
        } catch (PulsarAdminException.NotAuthorizedException e) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sinkName)

                    .attr("componentType", ComponentTypeUtils.toString(componentType))

                    .log("/ / Client is not authorized to operate on tenant");
            throw new RestException(Response.Status.UNAUTHORIZED, "Client is not authorized to perform operation");
        } catch (PulsarAdminException.NotFoundException e) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sinkName)

                    .attr("tenant3", tenant).log("/ / Tenant does not exist");
            throw new RestException(Response.Status.BAD_REQUEST, "Tenant does not exist");
        } catch (PulsarAdminException e) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sinkName)

                    .exception(e).log("/ / Issues getting tenant data");
            throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());
        }

        FunctionMetaDataManager functionMetaDataManager = worker().getFunctionMetaDataManager();

        if (functionMetaDataManager.containsFunction(tenant, namespace, sinkName)) {
            log.error().attr("componentType", ComponentTypeUtils.toString(componentType)).attr("tenant", tenant)

                    .attr("namespace", namespace).attr("componentName", sinkName).log("/ / already exists");

View on GitHub (pinned to 820761864e)

Solutions

  1. Grant the worker's role tenant admin rights: pulsar-admin tenants update tenant --admin-roles <worker-role>.
  2. Check namespace policies: pulsar-admin namespaces grant-permission tenant/ns --actions functions,sinks --role <worker-role>.
  3. Verify the worker's authentication plugin/parameters and that its token maps to the intended role.
  4. Inspect broker authorization logs to see which role/action was denied.

Example fix

// before: worker role not authorized
tenants.update(tenant, new TenantInfoImpl(Collections.emptySet(), Collections.emptySet()));
// after: include the worker role as tenant admin
pulsar-admin tenants update my-tenant --admin-roles functions-worker-role
Defensive patterns

Strategy: try-catch

Validate before calling

// verify authorization up front
admin.tenants().getTenantInfo(tenant); // throws NotAuthorizedException if the worker role lacks access
admin.namespaces().getPermissions(tenant + "/" + namespace);

Try / catch

try {
    sinks.registerSink(tenant, ns, name, cfg, null, null, null, authParams);
} catch (RestException e) {
    if (e.getResponse().getStatus() == 401) {
        // grant the worker role tenant admin / namespace functions+sinks permissions
    } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/022360f7acde8306. Report an issue: GitHub.