{"record":{"id":"8609ac4b1f416f09","repo":"apache/pulsar","slug":"cluster-already-exists","errorCode":null,"errorMessage":"Cluster already exists","messagePattern":"Cluster already exists","errorType":"http","errorClass":"RestException","httpStatus":409,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java","lineNumber":184,"sourceCode":"                )\n            )\n        ) ClusterDataImpl clusterData) {\n        validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.CREATE_CLUSTER)\n                .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync())\n                .thenCompose(__ -> {\n                    NamedEntity.checkName(cluster);\n                    if (clusterData == null) {\n                        throw new RestException(Status.BAD_REQUEST, \"cluster data is required\");\n                    }\n                    try {\n                        clusterData.checkPropertiesIfPresent();\n                    } catch (IllegalArgumentException ex) {\n                        throw new RestException(Status.BAD_REQUEST, ex.getMessage());\n                    }\n                    return clusterResources().getClusterAsync(cluster);\n                }).thenCompose(clusterOpt -> {\n                    if (clusterOpt.isPresent()) {\n                        throw new RestException(Status.CONFLICT, \"Cluster already exists\");\n                    }\n                    return clusterResources().createClusterAsync(cluster, clusterData);\n                }).thenAccept(__ -> {\n                    log.info().attr(\"cluster\", cluster).log(\"Created cluster\");\n                    asyncResponse.resume(Response.ok().build());\n                }).exceptionally(ex -> {\n                    log.error()\n                            .attr(\"cluster\", cluster)\n                            .exception(ex)\n                            .log(\"Failed to create cluster\");\n                    Throwable realCause = FutureUtil.unwrapCompletionException(ex);\n                    if (realCause instanceof IllegalArgumentException) {\n                        asyncResponse.resume(new RestException(PRECONDITION_FAILED,\n                                \"Cluster name is not valid\"));\n                        return null;\n                    }\n                    resumeAsyncResponseExceptionally(asyncResponse, ex);\n                    return null;","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java#L166-L202","documentation":"HTTP 409 (CONFLICT) thrown by the admin REST API when a client attempts to create a cluster whose name already exists in cluster metadata. The handler checks cluster existence asynchronously via clusterResources().getClusterAsync and throws before calling createClusterAsync. Cluster creation is idempotency-guarded: one name maps to one ClusterData record.","triggerScenarios":"POST /admin/v3/clusters/{cluster} where the cluster name is already present in the metadata store; concurrent createCluster calls racing on the same name; retrying a previously successful create request.","commonSituations":"Re-running bootstrap/provisioning scripts without checking existing clusters; two ops tools provisioning the same cluster concurrently; Terraform/Ansible re-apply after a partial failure where the cluster record was already written.","solutions":["Use PUT /admin/v3/clusters/{cluster} (update/upsert semantics) instead of POST if you want create-or-update behavior.","Check existence first with GET /admin/v3/clusters/{cluster}; if it returns 200 and config matches, treat the create as done.","Delete the stale cluster with DELETE /admin/v3/clusters/{cluster} if it is leftover garbage and empty, then recreate.","Pick a different, unique cluster name if the existing record is legitimate."],"exampleFix":"// before\nadmin.clusters().createCluster(clusterName, clusterData); // 409 if exists\n// after\ntry {\n    admin.clusters().createCluster(clusterName, clusterData);\n} catch (PulsarAdminException.ConflictException e) {\n    admin.clusters().updateCluster(clusterName, clusterData); // upsert\n}","handlingStrategy":"validation","validationCode":"boolean exists;\ntry {\n    admin.clusters().getCluster(clusterName);\n    exists = true;\n} catch (PulsarAdminException.NotFoundException e) {\n    exists = false;\n}\nif (exists) {\n    admin.clusters().updateCluster(clusterName, clusterData); // upsert instead of create\n} else {\n    admin.clusters().createCluster(clusterName, clusterData);\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.clusters().createCluster(clusterName, clusterData);\n} catch (PulsarAdminException.ConflictException e) {\n    // cluster already present: verify config then update\n    admin.clusters().updateCluster(clusterName, clusterData);\n}","preventionTips":["Prefer PUT/update (upsert) semantics in provisioning code instead of POST create.","Check GET /admin/v3/clusters/{cluster} before creating in idempotent automation.","Serialize cluster provisioning (single tool/lock) to avoid concurrent create races."],"tags":["rest-api","conflict","cluster-admin","duplicate-resource"],"backgroundTag":"resource-already-exists","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"}