{"record":{"id":"7d874ec463bc2149","repo":"SonarSource/sonarqube","slug":"the-quality-profile-cannot-be-restored-as-it-conta-7d874e","errorCode":null,"errorMessage":"The quality profile cannot be restored as it contains duplicates for the following rules: %s","messagePattern":"The quality profile cannot be restored as it contains duplicates for the following rules: (.+?)","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java","lineNumber":183,"sourceCode":"  private static List<ImportedRule> parseRuleActivations(SMInputCursor rulesCursor) throws XMLStreamException {\n    List<ImportedRule> activations = new ArrayList<>();\n    Set<RuleKey> activatedKeys = new HashSet<>();\n    List<RuleKey> duplicatedKeys = new ArrayList<>();\n    while (rulesCursor.getNext() != null) {\n      SMInputCursor ruleCursor = rulesCursor.childElementCursor();\n      Map<String, String> parameters = new HashMap<>();\n      ImportedRule rule = new ImportedRule();\n      readRule(ruleCursor, parameters, rule);\n\n      var ruleKey = rule.getRuleKey();\n      if (activatedKeys.contains(ruleKey)) {\n        duplicatedKeys.add(ruleKey);\n      }\n      activatedKeys.add(ruleKey);\n      activations.add(rule);\n    }\n    if (!duplicatedKeys.isEmpty()) {\n      throw new IllegalArgumentException(\"The quality profile cannot be restored as it contains duplicates for the following rules: \" +\n        duplicatedKeys.stream().map(RuleKey::toString).filter(Objects::nonNull).collect(Collectors.joining(\", \")));\n    }\n    return activations;\n  }\n\n  private static void readRule(SMInputCursor ruleCursor, Map<String, String> parameters, ImportedRule rule) throws XMLStreamException {\n    while (ruleCursor.getNext() != null) {\n      String nodeName = ruleCursor.getLocalName();\n      if (CS.equals(ATTRIBUTE_REPOSITORY_KEY, nodeName)) {\n        rule.setRepository(StringUtils.trim(ruleCursor.collectDescendantText(false)));\n      } else if (CS.equals(ATTRIBUTE_KEY, nodeName)) {\n        rule.setKey(StringUtils.trim(ruleCursor.collectDescendantText(false)));\n      } else if (CS.equals(ATTRIBUTE_TEMPLATE_KEY, nodeName)) {\n        rule.setTemplate(StringUtils.trim(ruleCursor.collectDescendantText(false)));\n      } else if (CS.equals(ATTRIBUTE_NAME, nodeName)) {\n        rule.setName(StringUtils.trim(ruleCursor.collectDescendantText(false)));\n      } else if (CS.equals(ATTRIBUTE_TYPE, nodeName)) {\n        rule.setType(StringUtils.trim(ruleCursor.collectDescendantText(false)));","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java#L165-L201","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Deduplicate the <rules> section: keep one <rule> per key, merging parameters as needed.","Re-export the profile from the source server rather than concatenating exports.","Pre-validate by parsing rule keys locally and refusing files with duplicates before upload.","If duplicates carry different parameters, decide which parameters win and edit the XML to a single entry."],"exampleFix":"// before\nrestoreProfile(concat(exportA, exportB)); // duplicate <rule> keys\n// after\nSet<String> seen = new HashSet<>();\nfor (Element rule : ruleElements(doc)) {\n  String key = rule.getAttribute(\"key\");\n  if (!seen.add(key)) {\n    rule.getParentNode().removeChild(rule); // keep first occurrence\n  }\n}\nrestoreProfile(new ByteArrayInputStream(serialized(doc)));","handlingStrategy":"validation","validationCode":"Set<String> keys = new HashSet<>();\nfor (Element rule : doc.getElementsByTagName(\"rule\")) {\n  if (!keys.add(((Element) rule).getAttribute(\"key\"))) {\n    throw new IllegalStateException(\"duplicate rule key in backup: \" + ((Element) rule).getAttribute(\"key\"));\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  restoreProfile(stream);\n} catch (SonarQubeClientException e) {\n  if (String.valueOf(e.getMessage()).contains(\"contains duplicates for the following rules\")) {\n    LOG.error(\"deduplicate <rules> entries in the backup before restoring\");\n  }\n  throw e;\n}","preventionTips":["Never concatenate profile exports; merge rule entries by key instead","Edit parameters in the existing <rule> entry rather than adding a second one","Validate backup XML for duplicate rule keys before upload"],"tags":["sonarqube","webapi","quality-profile","xml","duplicates"],"backgroundTag":"schema-validation-failed","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}