SonarSource/sonarqube · error · IllegalArgumentException
Specified RuleKey '%s' is not equal to the one already regis
Error message
Specified RuleKey '%s' is not equal to the one already registered in repository for ref %s: '%s'
What it means
RuleRepositoryImpl.register() keeps a map from a dump ref to the rule registered under it. If a ref is registered twice with a different RuleKey than the one already stored, an IllegalArgumentException is thrown because two different rules are being mapped to the same reference, which would corrupt the dump's rule index. Registering the same identical RuleKey under a ref is idempotent and returns the existing Rule.
Source
Thrown at server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/rule/RuleRepositoryImpl.java:41
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.sonar.api.rule.RuleKey;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
public class RuleRepositoryImpl implements RuleRepository {
private final Map<String, Rule> rulesByUuid = new HashMap<>();
@Override
public Rule register(String ref, RuleKey ruleKey) {
requireNonNull(ruleKey, "ruleKey can not be null");
Rule rule = rulesByUuid.get(ref);
if (rule != null) {
if (!ruleKey.repository().equals(rule.repository()) || !ruleKey.rule().equals(rule.key())) {
throw new IllegalArgumentException(format(
"Specified RuleKey '%s' is not equal to the one already registered in repository for ref %s: '%s'",
ruleKey, ref, RuleKey.of(rule.repository(), rule.key())));
}
return rule;
}
rule = new Rule(ref, ruleKey.repository(), ruleKey.rule());
rulesByUuid.put(ref, rule);
return rule;
}
@Override
public Collection<Rule> getAll() {
return List.copyOf(rulesByUuid.values());
}
}
View on GitHub (pinned to 184c821202)
Solutions
- Find which step calls register() with the colliding ref and why two distinct RuleKeys map to it
- Ensure refs are derived from a unique property of the rule (uuid or full RuleKey) instead of a colliding value
- If the ref should map to the same rule, verify the exact repository and rule name spelling (case) matches the earlier registration
Example fix
// before: ref derived from rule name only, can collide across repos String ref = hash(rule.key()); // after: include repository in ref String ref = hash(rule.repository() + ":" + rule.key());
Defensive patterns
Strategy: validation
Validate before calling
Rule existing = repositoryLookup(ref);
if (existing != null && !ruleKey.repository().equals(existing.repository())) {
throw new IllegalArgumentException("ref collision: " + ref);
} Try / catch
try { ruleRepository.register(ref, ruleKey); } catch (IllegalArgumentException e) { logger.error("Ref {} already maps to a different rule", ref, e); } Prevention
- Derive refs from unique rule identity (uuid or repository:name), never from colliding hashes
- Check for an existing registration before registering a new ref
- Write unit tests covering duplicate ref registration
When it happens
Trigger: Calling register(ref, ruleKey) for a ref that already holds a Rule whose repository() or key() differs from the supplied RuleKey — i.e. a ref/reason collision between two distinct rules during export.
Common situations: A bug in a step computing refs (hash/ID collisions) reusing the same ref for different rules; re-registering rules from different repositories under the same ref during a custom/patched export.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Rule Export failed after processing %d rules successfully
- Ad-hoc rules export failed after processing %d rules success
- Metadata has already been written
- Can not write to file
- Metadata is missing
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/d1a69e2f4d2248dd.
Report an issue: GitHub.