{"record":{"id":"884009c21bd3c504","repo":"apache/pulsar","slug":"tenant-does-not-exist-884009","errorCode":null,"errorMessage":"Tenant does not exist","messagePattern":"Tenant does not exist","errorType":"http","errorClass":"RestException","httpStatus":404,"severity":"warning","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProvider.java","lineNumber":157,"sourceCode":"                                    return Optional.empty();\n                                }\n                                log.error().attr(\"tenant\", tenantName).exception(cause).log(\"Failed to get tenant\");\n                                throw new RestException(cause);\n                            })\n                            .thenCompose(op -> {\n                                if (op.isPresent()) {\n                                    TenantInfo tenantInfo = op.get();\n                                    if (tenantInfo.getAdminRoles() == null || tenantInfo.getAdminRoles().isEmpty()) {\n                                        return CompletableFuture.completedFuture(false);\n                                    }\n\n                                    return CompletableFuture.completedFuture(roles.stream()\n                                            .anyMatch(n -> tenantInfo.getAdminRoles().contains(n)));\n                                }\n                                // A client naming a tenant that does not exist is a client error, not a broker\n                                // fault: reject it without logging. Any client can trigger this at will, and the\n                                // caller (e.g. ServerCnx) already logs the rejection at its own level.\n                                throw new RestException(Response.Status.NOT_FOUND, \"Tenant does not exist\");\n                            });\n                });\n    }\n\n    @SuppressWarnings({\"deprecation\", \"unchecked\"})\n    private Set<String> getRoles(String role, AuthenticationDataSource authData) {\n        if (authData == null || (authData instanceof AuthenticationDataSubscription\n                && ((AuthenticationDataSubscription) authData).getAuthData() == null)) {\n            return Collections.singleton(role);\n        }\n\n        String token = null;\n\n        if (authData.hasDataFromCommand()) {\n            // Authenticate Pulsar binary connection\n            token = authData.getCommandData();\n            if (StringUtils.isBlank(token)) {\n                return Collections.emptySet();","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/MultiRolesTokenAuthorizationProvider.java#L139-L175","documentation":"validateTenantAdminAccess in MultiRolesTokenAuthorizationProvider completes with a 404 RestException when the tenant named in the authorization request has no metadata in the metadata store. Per the source comment, a client naming a nonexistent tenant is a client error and is rejected without broker-side logging.","triggerScenarios":"Calling an admin/authorization API (e.g. grantPermission or canLookup-style checks) with a tenant name that was never created, was deleted, or is misspelled in the request.","commonSituations":"Tenant deleted between when a script/config was written and when it ran; typo in tenant name in automation scripts or CI; case-sensitivity mismatch; multi-cluster setup where the tenant only exists on a different cluster's metadata store.","solutions":["Verify the tenant exists: `pulsar-admin tenants list` and correct the tenant name in the request.","Create the missing tenant if it was never provisioned: `pulsar-admin tenants create <tenant> -r <admin-role>`.","Check the broker is connected to the intended configuration/metadata store (cluster may not have this tenant).","Handle HTTP 404 from the admin API in client code as 'tenant not found' rather than a permissions bug."],"exampleFix":"// before\nboolean ok = auth.checkAuthorization(tenant, ...); // tenant=\"mytenant\" (typo, actual: my-tenant)\n// after\n// create or correct the tenant first\npulsarAdmin.tenants().createTenant(\"my-tenant\", new TenantInfoImpl(adminRoles, allowedClusters));","handlingStrategy":"validation","validationCode":"Set<String> tenants = admin.tenants().getTenants();\nif (!tenants.contains(tenant)) throw new IllegalArgumentException(\"tenant does not exist: \" + tenant);","typeGuard":"boolean tenantExists(PulsarAdmin admin, String tenant) { try { return admin.tenants().getTenants().contains(tenant); } catch (Exception e) { return false; } }","tryCatchPattern":"try { ...authorization check... } catch (RestException e) { if (e.getResponse().getStatus() == 404) { /* tenant not found: fix request */ } else throw e; }","preventionTips":["List tenants with `pulsar-admin tenants list` before scripted operations","Watch for tenant deletion in other automation","Mind case-sensitivity of tenant names","Confirm the cluster's metadata store actually hosts the tenant"],"tags":["authorization","tenant","not-found","rest"],"backgroundTag":"tenant-not-found","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}