SonarSource/sonarqube · error · IllegalArgumentException

The quality profile cannot be restored as it contains duplic

Error message

The quality profile cannot be restored as it contains duplicates for the following rules: %s

What it means

QProfileParser.parseRuleActivations detects duplicate rule activations in a profile backup: the same rule key appearing more than once in <rules>. To keep restored profiles deterministic it throws IllegalArgumentException listing the duplicated rule keys.

Source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java:183

  private static List<ImportedRule> parseRuleActivations(SMInputCursor rulesCursor) throws XMLStreamException {
    List<ImportedRule> activations = new ArrayList<>();
    Set<RuleKey> activatedKeys = new HashSet<>();
    List<RuleKey> duplicatedKeys = new ArrayList<>();
    while (rulesCursor.getNext() != null) {
      SMInputCursor ruleCursor = rulesCursor.childElementCursor();
      Map<String, String> parameters = new HashMap<>();
      ImportedRule rule = new ImportedRule();
      readRule(ruleCursor, parameters, rule);

      var ruleKey = rule.getRuleKey();
      if (activatedKeys.contains(ruleKey)) {
        duplicatedKeys.add(ruleKey);
      }
      activatedKeys.add(ruleKey);
      activations.add(rule);
    }
    if (!duplicatedKeys.isEmpty()) {
      throw new IllegalArgumentException("The quality profile cannot be restored as it contains duplicates for the following rules: " +
        duplicatedKeys.stream().map(RuleKey::toString).filter(Objects::nonNull).collect(Collectors.joining(", ")));
    }
    return activations;
  }

  private static void readRule(SMInputCursor ruleCursor, Map<String, String> parameters, ImportedRule rule) throws XMLStreamException {
    while (ruleCursor.getNext() != null) {
      String nodeName = ruleCursor.getLocalName();
      if (CS.equals(ATTRIBUTE_REPOSITORY_KEY, nodeName)) {
        rule.setRepository(StringUtils.trim(ruleCursor.collectDescendantText(false)));
      } else if (CS.equals(ATTRIBUTE_KEY, nodeName)) {
        rule.setKey(StringUtils.trim(ruleCursor.collectDescendantText(false)));
      } else if (CS.equals(ATTRIBUTE_TEMPLATE_KEY, nodeName)) {
        rule.setTemplate(StringUtils.trim(ruleCursor.collectDescendantText(false)));
      } else if (CS.equals(ATTRIBUTE_NAME, nodeName)) {
        rule.setName(StringUtils.trim(ruleCursor.collectDescendantText(false)));
      } else if (CS.equals(ATTRIBUTE_TYPE, nodeName)) {
        rule.setType(StringUtils.trim(ruleCursor.collectDescendantText(false)));

View on GitHub (pinned to 184c821202)

Solutions

  1. Deduplicate the <rules> section: keep one <rule> per key, merging parameters as needed.
  2. Re-export the profile from the source server rather than concatenating exports.
  3. Pre-validate by parsing rule keys locally and refusing files with duplicates before upload.
  4. If duplicates carry different parameters, decide which parameters win and edit the XML to a single entry.

Example fix

// before
restoreProfile(concat(exportA, exportB)); // duplicate <rule> keys
// after
Set<String> seen = new HashSet<>();
for (Element rule : ruleElements(doc)) {
  String key = rule.getAttribute("key");
  if (!seen.add(key)) {
    rule.getParentNode().removeChild(rule); // keep first occurrence
  }
}
restoreProfile(new ByteArrayInputStream(serialized(doc)));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> keys = new HashSet<>();
for (Element rule : doc.getElementsByTagName("rule")) {
  if (!keys.add(((Element) rule).getAttribute("key"))) {
    throw new IllegalStateException("duplicate rule key in backup: " + ((Element) rule).getAttribute("key"));
  }
}

Try / catch

try {
  restoreProfile(stream);
} catch (SonarQubeClientException e) {
  if (String.valueOf(e.getMessage()).contains("contains duplicates for the following rules")) {
    LOG.error("deduplicate <rules> entries in the backup before restoring");
  }
  throw e;
}

Prevention

When it happens

Trigger: POST api/qualityprofiles/restore with a backup XML that contains two <rule> entries with the same key (with or without differing parameters). Merged/concatenated backups from multiple exports; hand-edited files duplicating a rule block.

Common situations: Merging profile exports from different servers that share rules; scripted XML merging that appended instead of replacing; manual edits re-adding a rule to change its parameters instead of editing the existing entry.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/7d874ec463bc2149. Report an issue: GitHub.