{"record":{"id":"482dc32bfc30e313","repo":"SonarSource/sonarqube","slug":"the-quality-profile-cannot-be-restored-as-it-conta","errorCode":null,"errorMessage":"The quality profile cannot be restored as it contains rules from external rule engines: %s","messagePattern":"The quality profile cannot be restored as it contains rules from external rule engines: (.+?)","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java","lineNumber":197,"sourceCode":"\n      List<RuleDto> rulesBasedOnDeprecatedKeys = db.ruleDao().selectByUuids(dbSession, deprecatedRuleKeysByUuid.keySet());\n      for (RuleDto rule : rulesBasedOnDeprecatedKeys) {\n        DeprecatedRuleKeyDto deprecatedRuleKey = deprecatedRuleKeysByUuid.get(rule.getUuid());\n        RuleKey oldRuleKey = RuleKey.of(deprecatedRuleKey.getOldRepositoryKey(), deprecatedRuleKey.getOldRuleKey());\n        ruleDtos.put(oldRuleKey, rule);\n      }\n    }\n\n    return ruleDtos;\n  }\n\n  private static void checkIfRulesFromExternalEngines(Collection<RuleDto> ruleDefinitions) {\n    List<RuleDto> externalRules = ruleDefinitions.stream()\n      .filter(RuleDto::isExternal)\n      .toList();\n\n    if (!externalRules.isEmpty()) {\n      throw new IllegalArgumentException(\"The quality profile cannot be restored as it contains rules from external rule engines: \"\n        + externalRules.stream().map(r -> r.getKey().toString()).collect(Collectors.joining(\", \")));\n    }\n  }\n\n  private Map<RuleKey, RuleDto> createCustomRulesIfNotExist(DbSession dbSession, List<ImportedRule> rules, Map<RuleKey, RuleDto> ruleDefinitionsByKey) {\n    List<NewCustomRule> customRulesToCreate = rules.stream()\n      .filter(r -> ruleDefinitionsByKey.get(r.getRuleKey()) == null && r.isCustomRule())\n      .map(QProfileBackuperImpl::importedRuleToNewCustomRule)\n      .toList();\n\n    if (!customRulesToCreate.isEmpty()) {\n      return db.ruleDao().selectByKeys(dbSession, ruleCreator.restore(dbSession, customRulesToCreate).stream().map(RuleDto::getKey).toList())\n        .stream()\n        .collect(Collectors.toMap(RuleDto::getKey, identity()));\n    }\n    return Collections.emptyMap();\n  }\n","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java#L179-L215","documentation":"QProfileBackuperImpl.checkIfRulesFromExternalEngines rejects restoring a quality profile backup when its rule definitions include external (external-engine) rules, because such rules are managed by their analyzers and cannot be created/activated via profile restore. It throws IllegalArgumentException listing the offending rule keys.","triggerScenarios":"POST api/qualityprofiles/restore with a backup XML whose <rules> section contains rules marked external (from plugins like External Analyzer reports). Re-importing a profile exported from a server where external rules were recorded in the backup.","commonSituations":"Backups taken from SonarQube versions that embedded external rules in exports, restored on instances without the corresponding external analyzer plugin; CI provisioning pipelines restoring old profile XML files.","solutions":["Strip <rule> entries for external rules from the backup XML before restoring (rules will be reactivated once the external analyzer plugin runs).","Re-export the backup from a current SonarQube version that excludes external rules.","Install/enable the external analyzer plugin so the rules exist natively, and let it register the profile instead of restoring a backup.","Wrap restore with a pre-parse that fails fast and reports the offending rule keys."],"exampleFix":"// before\nrestoreProfile(xmlBackupStream); // IllegalArgumentException listing external rules\n// after\nDocument doc = parse(xmlBackupStream);\nremoveExternalRuleEntries(doc); // drop rules flagged as external engines\nrestoreProfile(new ByteArrayInputStream(serialized(doc)));","handlingStrategy":"validation","validationCode":"// pre-parse the backup and fail fast on external rules\nSet<String> external = readRuleKeys(xml).stream()\n  .filter(this::isExternalRuleKey) // keys from external-engine plugins\n  .collect(Collectors.toSet());\nif (!external.isEmpty()) throw new IllegalStateException(\"backup contains external rules: \" + external);","typeGuard":null,"tryCatchPattern":"try {\n  restoreProfile(xmlStream);\n} catch (SonarQubeClientException e) {\n  if (String.valueOf(e.getMessage()).contains(\"rules from external rule engines\")) {\n    LOG.error(\"strip external rules or install the analyzer plugin before restoring\");\n  }\n  throw e;\n}","preventionTips":["Use fresh exports from the same or newer SonarQube version (external rules excluded)","Do not hand-merge old backups containing external rule entries","Install external analyzer plugins instead of restoring profiles that activate their rules"],"tags":["sonarqube","webapi","quality-profile","external-rules","restore"],"backgroundTag":"unsupported-operation","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"}