SonarSource/sonarqube · error · IllegalArgumentException
A rule with the key ' ' already exists
Error message
A rule with the key '%s' already exists
What it means
RuleCreator.updateExistingRule throws this IllegalArgumentException when an update operation reaches the 'create' branch of the rule creation logic, meaning a rule with the given key already exists in the database. It guards against inserting a duplicate rule key when the caller expected to create a new rule.
Solutions
- Check rule existence first via api/rules/show?key=... or RuleDao.selectRuleByKey and use the update endpoint (api/rules/update) instead of create.
- Make provisioning scripts idempotent: create if absent, update if present.
- Use a different, unique rule key if you truly intend a new rule.
- Serialize rule provisioning so concurrent jobs cannot race on the same key.
Example fix
// before
ruleUpdater.create(createRequest); // fails when key exists
// after
if (ruleDao.selectRuleByKey(dbSession, key).isPresent()) {
ruleUpdater.update(updateRequest);
} else {
ruleUpdater.create(createRequest);
} Defensive patterns
Strategy: validation
Validate before calling
RuleDto existing = dbClient.ruleDao().selectRuleByKey(dbSession, key).orElse(null);
if (existing != null) { /* update instead of create */ } Try / catch
try { creator.create(req); } catch (IllegalArgumentException e) { if (e.getMessage().contains("already exists")) { updater.update(toUpdate(req)); } else { throw e; } } Prevention
- Look up the rule by key before creating
- Make provisioning pipelines idempotent
- Use api/rules/update for existing keys
- Lock rule-creation jobs to a single runner
When it happens
Trigger: Calling the rules/create WS (or RuleCreator.create) with a rule key that already exists in the rule table, so the DAO lookup finds an existing ruleDto and control falls into the else branch that throws.
Common situations: Re-running an automation script that provisions custom rules without idempotency checks; importing a rules profile that already defines the rule; two CI jobs creating the same custom rule concurrently.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- A removed rule with the key
- Specified RuleKey ' ' is not equal to the one already…
- a JVM option can't be empty and must start with '-'. The…
- a JVM option can't overwrite mandatory JVM options. The…
- a JVM option can't overwrite mandatory JVM options.
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/d0227ca98797b812.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-webserver-common/src/main/java/org/sonar/server/common/rule/RuleCreator.java:292
} else {
ruleDto.setStatus(RuleStatus.READY)
.setName(newRule.name())
.replaceRuleDescriptionSectionDtos(Set.of(
createDefaultRuleDescriptionSection(uuidFactory.create(), newRule.markdownDescription())))
.setUpdatedAt(system2.now());
ruleDto.replaceAllDefaultImpacts(Set.of());
setCleanCodeAttributeAndImpacts(newRule, ruleDto, templateRule);
dbClient.ruleDao().update(dbSession, ruleDto);
for (RuleParamDto ruleParamDto : dbClient.ruleDao().selectRuleParamsByRuleKey(dbSession, ruleDto.getKey())) {
String newValue = Strings.emptyToNull(newRule.parameter(ruleParamDto.getName()));
ruleParamDto.setDefaultValue(newValue);
dbClient.ruleDao().updateRuleParam(dbSession, ruleDto, ruleParamDto);
}
}
} else {
throw new IllegalArgumentException(format("A rule with the key '%s' already exists", ruleDto.getKey().rule()));
}
return ruleDto;
}
}
View on GitHub (pinned to 184c821202)