SonarSource/sonarqube · error · IllegalArgumentException

The quality profile cannot be restored as it contains rules

Error message

The quality profile cannot be restored as it contains rules from external rule engines: %s

What it means

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.

Source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java:197

      List<RuleDto> rulesBasedOnDeprecatedKeys = db.ruleDao().selectByUuids(dbSession, deprecatedRuleKeysByUuid.keySet());
      for (RuleDto rule : rulesBasedOnDeprecatedKeys) {
        DeprecatedRuleKeyDto deprecatedRuleKey = deprecatedRuleKeysByUuid.get(rule.getUuid());
        RuleKey oldRuleKey = RuleKey.of(deprecatedRuleKey.getOldRepositoryKey(), deprecatedRuleKey.getOldRuleKey());
        ruleDtos.put(oldRuleKey, rule);
      }
    }

    return ruleDtos;
  }

  private static void checkIfRulesFromExternalEngines(Collection<RuleDto> ruleDefinitions) {
    List<RuleDto> externalRules = ruleDefinitions.stream()
      .filter(RuleDto::isExternal)
      .toList();

    if (!externalRules.isEmpty()) {
      throw new IllegalArgumentException("The quality profile cannot be restored as it contains rules from external rule engines: "
        + externalRules.stream().map(r -> r.getKey().toString()).collect(Collectors.joining(", ")));
    }
  }

  private Map<RuleKey, RuleDto> createCustomRulesIfNotExist(DbSession dbSession, List<ImportedRule> rules, Map<RuleKey, RuleDto> ruleDefinitionsByKey) {
    List<NewCustomRule> customRulesToCreate = rules.stream()
      .filter(r -> ruleDefinitionsByKey.get(r.getRuleKey()) == null && r.isCustomRule())
      .map(QProfileBackuperImpl::importedRuleToNewCustomRule)
      .toList();

    if (!customRulesToCreate.isEmpty()) {
      return db.ruleDao().selectByKeys(dbSession, ruleCreator.restore(dbSession, customRulesToCreate).stream().map(RuleDto::getKey).toList())
        .stream()
        .collect(Collectors.toMap(RuleDto::getKey, identity()));
    }
    return Collections.emptyMap();
  }

View on GitHub (pinned to 184c821202)

Solutions

  1. Strip <rule> entries for external rules from the backup XML before restoring (rules will be reactivated once the external analyzer plugin runs).
  2. Re-export the backup from a current SonarQube version that excludes external rules.
  3. Install/enable the external analyzer plugin so the rules exist natively, and let it register the profile instead of restoring a backup.
  4. Wrap restore with a pre-parse that fails fast and reports the offending rule keys.

Example fix

// before
restoreProfile(xmlBackupStream); // IllegalArgumentException listing external rules
// after
Document doc = parse(xmlBackupStream);
removeExternalRuleEntries(doc); // drop rules flagged as external engines
restoreProfile(new ByteArrayInputStream(serialized(doc)));
Defensive patterns

Strategy: validation

Validate before calling

// pre-parse the backup and fail fast on external rules
Set<String> external = readRuleKeys(xml).stream()
  .filter(this::isExternalRuleKey) // keys from external-engine plugins
  .collect(Collectors.toSet());
if (!external.isEmpty()) throw new IllegalStateException("backup contains external rules: " + external);

Try / catch

try {
  restoreProfile(xmlStream);
} catch (SonarQubeClientException e) {
  if (String.valueOf(e.getMessage()).contains("rules from external rule engines")) {
    LOG.error("strip external rules or install the analyzer plugin before restoring");
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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