apache/pulsar · error · RestException

Tenant does not exist

Error message

Tenant does not exist

What it means

validateAdminAccessForTenantAsync first loads the tenant via PulsarResources' tenant resources. If the tenant does not exist in metadata storage, it throws RestException with HTTP 404 'Tenant does not exist' before any authorization checks are made.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:337

     */
    protected CompletableFuture<Void> validateAdminAccessForTenantAsync(String tenant) {
        return validateAdminAccessForTenantAsync(pulsar(), clientAppId(), originalPrincipal(), tenant,
                clientAuthData());
    }

    protected CompletableFuture<Void> validateAdminAccessForTenantAsync(
            PulsarService pulsar, String clientAppId,
            String originalPrincipal, String tenant,
            AuthenticationDataSource authenticationData) {
            log.debug()
                    .attr("tenant", tenant)
                    .attr("authenticated", (isClientAuthenticated(clientAppId)))
                    .attr("role", clientAppId)
                    .log("check admin access on tenant");
                return pulsar.getPulsarResources().getTenantResources().getTenantAsync(tenant)
                .thenCompose(tenantInfoOptional -> {
                    if (tenantInfoOptional.isEmpty()) {
                        throw new RestException(Status.NOT_FOUND, "Tenant does not exist");
                    }
                    TenantInfo tenantInfo = tenantInfoOptional.get();
                    if (pulsar.getConfiguration().isAuthenticationEnabled() && pulsar.getConfiguration()
                            .isAuthorizationEnabled()) {
                        if (!isClientAuthenticated(clientAppId)) {
                            throw new RestException(Status.FORBIDDEN, "Need to authenticate to perform the request");
                        }
                        validateOriginalPrincipal(clientAppId, originalPrincipal);
                        if (pulsar.getConfiguration().getProxyRoles().contains(clientAppId)) {
                            AuthorizationService authorizationService =
                                    pulsar.getBrokerService().getAuthorizationService();
                            return authorizationService.isTenantAdmin(tenant, clientAppId, tenantInfo,
                                            authenticationData)
                                .thenCompose(isTenantAdmin -> {
                                    if (!isTenantAdmin) {
                                            return authorizationService.isSuperUser(clientAppId, authenticationData)
                                                .thenCombine(authorizationService.isSuperUser(originalPrincipal,
                                                             authenticationData),

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the tenant name in the URL path is correct (GET /admin/v2/tenants to list existing tenants)
  2. Create the tenant first: PUT /admin/v2/tenants/<tenant> with adminRoles/allowedClusters
  3. Point the client at the correct cluster/instance where the tenant exists
  4. Check ZK/metadata store for the tenant if you suspect replication or metadata issues

Example fix

// before
curl http://broker:8080/admin/v2/namespaces/mytennt/clusters
// after
# list tenants, then use/create the right one
curl http://broker:8080/admin/v2/tenants
curl -X PUT -H "Content-Type: application/json" -d '{"adminRoles":["admin"],"allowedClusters":["standalone"]}' http://broker:8080/admin/v2/tenants/mytenant
Defensive patterns

Strategy: try-catch

Validate before calling

// caller-side pre-check
boolean exists = admin.tenants().getList().contains(tenant);
if (!exists) { throw new IllegalStateException("Tenant not found: " + tenant); }

Try / catch

try {
    admin.namespaces().getNamespaces(tenant);
} catch (PulsarAdminException e) {
    if (e.getStatusCode() == 404) {
        // create the tenant or fix the tenant name
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling any tenant-scoped admin REST endpoint (namespaces, topics under a tenant) with a misspelled or deleted tenant name; operating against the wrong cluster/environment whose metadata lacks the tenant; tenant deleted concurrently.

Common situations: Typos in tenant names in scripts/dashboards; migrating clients between clusters where the tenant wasn't created; cleanup jobs removing tenants still referenced by automation; wrong tenant part in the REST path (admin/v2/<tenant>/...).

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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