{"record":{"id":"5844172ad9b5e589","repo":"apache/pulsar","slug":"clusters-do-not-exist","errorCode":null,"errorMessage":"Clusters do not exist","messagePattern":"Clusters do not exist","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java","lineNumber":323,"sourceCode":"\n        Set<String> cleanedClusters = allowedClusters.stream()\n                .filter(c -> !StringUtils.isBlank(c))\n                .collect(Collectors.toSet());\n        if (cleanedClusters.isEmpty() || allowedClusters.stream().anyMatch(StringUtils::isBlank)) {\n            log.warn(\"Validation failed: allowed clusters are empty or contain blanks\");\n            return FutureUtil.failedFuture(\n                    new RestException(Status.PRECONDITION_FAILED, \"Clusters cannot be empty or blank\"));\n        }\n\n        return clusterResources().listAsync().thenAccept(availableClusters -> {\n            List<String> nonexistentClusters = allowedClusters.stream()\n                    .filter(cluster -> !availableClusters.contains(cluster))\n                    .collect(Collectors.toList());\n            if (nonexistentClusters.size() > 0) {\n                log.warn()\n                        .attr(\"clusters\", nonexistentClusters)\n                        .log(\"Failed to validate due to clusters do not exist\");\n                throw new RestException(Status.PRECONDITION_FAILED, \"Clusters do not exist\");\n            }\n        });\n    }\n\n    private CompletableFuture<Void> validateAdminRoleAsync(TenantInfoImpl info) {\n        if (info.getAdminRoles() != null && !info.getAdminRoles().isEmpty()) {\n            for (String adminRole : info.getAdminRoles()) {\n                if (!StringUtils.trim(adminRole).equals(adminRole)) {\n                    log.warn()\n                            .attr(\"adminRole\", adminRole)\n                            .log(\"Failed to validate due to adminRole contains whitespace in the beginning or end.\");\n                    return FutureUtil.failedFuture(new RestException(Status.PRECONDITION_FAILED,\n                            \"AdminRoles contains whitespace in the beginning or end.\"));\n                }\n            }\n        }\n        return CompletableFuture.completedFuture(null);\n    }","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java#L305-L341","documentation":"HTTP 412 PRECONDITION_FAILED raised by validateClustersAsync when a tenant creation/update request lists clusters that do not exist in the broker's cluster registry. The broker compares requested allowedClusters against availableClusters and rejects if any are missing.","triggerScenarios":"PUT/POST /admin/v2/tenants/{tenant} whose TenantInfo.allowedClusters (or clusters in the JSON body) contains cluster names not registered via PUT /admin/v2/clusters/{cluster}.","commonSituations":"Typo in cluster name; copying tenant config from another Pulsar installation; cluster deregistered or not yet provisioned; case-sensitivity mismatches; cross-cluster replication setups where the peer cluster was never onboarded.","solutions":["Register the missing cluster: PUT /admin/v2/clusters/{cluster} with its service URL, or remove it from the tenant's allowedClusters.","Verify existing clusters with GET /admin/v2/clusters and correct any typos in the request body.","If migrating configs, update tenant bodies to only reference clusters present in the target installation.","Retry after cluster provisioning completes if clusters are created by automation concurrently."],"exampleFix":"// before\nTenantInfo info = TenantInfo.builder()\n    .adminRoles(Set.of(\"admin\"))\n    .allowedClusters(Set.of(\"cluster-a\", \"cluster-b\")) // cluster-b not registered\n    .build();\n// after\nSet<String> available = admin.clusters().getClusters();\nTenantInfo info = TenantInfo.builder()\n    .adminRoles(Set.of(\"admin\"))\n    .allowedClusters(Sets.intersection(Set.of(\"cluster-a\", \"cluster-b\"), new HashSet<>(available)))\n    .build();","handlingStrategy":"validation","validationCode":"Set<String> available = new HashSet<>(admin.clusters().getClusters());\nSet<String> requested = tenantInfo.getAllowedClusters();\nif (!available.containsAll(requested)) {\n    Set<String> missing = new HashSet<>(requested);\n    missing.removeAll(available);\n    throw new IllegalArgumentException(\"Clusters do not exist: \" + missing);\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.tenants().createTenant(tenant, info);\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 412 && e.getMessage().contains(\"Clusters do not exist\")) {\n        // correct allowedClusters against admin.clusters().getClusters() and retry\n    }\n}","preventionTips":["Diff allowedClusters against GET /admin/v2/clusters before every tenant create/update.","Register all replication target clusters before referencing them in tenants.","Automate cluster onboarding so tenant configs never reference absent clusters.","Watch for typos and case mismatches in cluster names."],"tags":["rest-api","tenant","cluster","validation"],"backgroundTag":"unknown-cluster-reference","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"}