apache/pulsar · error · PulsarAdminException
Resource group already exists:${rgName}
Error message
Resource group already exists:${rgName} What it means
Thrown as PulsarAdminException when creating a resource group whose name already exists in the broker's resource-group map. Resource group names must be unique, so a duplicate create is rejected instead of overwriting the existing config.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/resourcegroup/ResourceGroupService.java:816
final long periodInSecs = pulsar.getConfiguration().getResourceUsageTransportPublishIntervalInSecs();
this.aggregateLocalUsagePeriodInSeconds = this.resourceUsagePublishPeriodInSeconds = periodInSecs;
// if any tenant/namespace registrations already exist, maybeStartSchedulers() will start the schedulers now.
maybeStartSchedulers();
}
private void checkRGCreateParams(String rgName, org.apache.pulsar.common.policies.data.ResourceGroup rgConfig)
throws PulsarAdminException {
if (rgConfig == null) {
throw new IllegalArgumentException("ResourceGroupCreate: Invalid null ResourceGroup config");
}
if (rgName.isEmpty()) {
throw new IllegalArgumentException("ResourceGroupCreate: can't create resource group with an empty name");
}
ResourceGroup rg = getResourceGroupInternal(rgName);
if (rg != null) {
throw new PulsarAdminException("Resource group already exists:" + rgName);
}
}
@Getter
private final PulsarService pulsar;
protected final ResourceQuotaCalculator quotaCalculator;
private ResourceUsageTransportManager resourceUsageTransportManagerMgr;
// rgConfigListener is used only through its side effects in the ctors, to set up RG/NS loading in config-listeners.
private final ResourceGroupConfigListener rgConfigListener;
// Given a RG-name, get the resource-group
private ConcurrentHashMap<String, ResourceGroup> resourceGroupsMap = new ConcurrentHashMap<>();
// Given a tenant-name, record its associated resource-group
private ConcurrentHashMap<String, ResourceGroup> tenantToRGsMap = new ConcurrentHashMap<>();
// Given a qualified NS-name (i.e., in "tenant/namespace" format), record its associated resource-groupView on GitHub (pinned to 820761864e)
Solutions
- Check existence first (getResourceGroupInternal / admin GET) and update instead of create if present
- Use an update API (or create-or-update pattern) for idempotent provisioning
- Serialize provisioning so concurrent jobs don't race
- Catch PulsarAdminException with 'already exists' in the message and treat as success in retry logic
Example fix
// before
admin.resourcegroups().createResourceGroup("rg1", rg); // fails on rerun
// after
try {
admin.resourcegroups().createResourceGroup("rg1", rg);
} catch (PulsarAdminException e) {
if (!String.valueOf(e.getMessage()).contains("already exists")) throw e;
admin.resourcegroups().updateResourceGroup("rg1", rg);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (admin.resourcegroups().getResourceGroup(rgName) != null) {
admin.resourcegroups().updateResourceGroup(rgName, rgConfig);
} else {
admin.resourcegroups().createResourceGroup(rgName, rgConfig);
} Try / catch
try {
admin.resourcegroups().createResourceGroup(rgName, rgConfig);
} catch (PulsarAdminException e) {
if (String.valueOf(e.getMessage()).startsWith("Resource group already exists")) {
admin.resourcegroups().updateResourceGroup(rgName, rgConfig);
} else throw e;
} Prevention
- Make provisioning scripts idempotent (create-or-update)
- Serialize provisioning jobs to avoid duplicate-creation races
- Treat 'already exists' as non-fatal in retry wrappers
When it happens
Trigger: Calling createResourceGroup with a name that was previously created — re-running an initialization script, two services racing to bootstrap the same group, or a retry after a timeout where the first attempt actually succeeded.
Common situations: Idempotency issues in deploy scripts; concurrent provisioning jobs; migrating config where the group already exists on the target cluster.
Related errors
- ${loadManagerClass} does not support this operation
- Unauthorized to validateBothSuperuserAndBrokerOperation for
- Cannot delete non empty namespace
- Cannot delete non empty bundle
- %s is a non-partitioned topic. Instead of calling delete-par
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/f2cd7abf626bcddf.
Report an issue: GitHub.