SonarSource/sonarqube · error · IllegalArgumentException

Unsupported component qualifier '%s'

Error message

Unsupported component qualifier '%s'

What it means

getEntityTypeForQualifier maps a component qualifier (PROJECT, VIEW, APP) to an EntityType used during component deletion/purge. Any other qualifier reaching it throws this IllegalArgumentException — the service only knows how to clean up these three component kinds.

Source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java:112

    dbClient.userDao().cleanHomepage(dbSession, entity);
    if (ComponentQualifiers.PROJECT.equals(entity.getQualifier())) {
      dbClient.userTokenDao().deleteByProjectUuid(dbSession, entity.getKey(), entity.getUuid());
    }
    // Note that we do not send an event for each individual branch being deleted with the project
    indexers.commitAndIndexEntities(dbSession, singletonList(entity), EntityEvent.DELETION);
  }

  private void deleteHistoryForEntity(DbSession dbSession, String entityId, EntityType entityType) {
    issueCountHistoryRepository.deleteHistoryForEntity(dbSession, entityId, entityType);
    measureHistoryRepository.deleteHistoryForEntity(dbSession, entityId, entityType);
  }

  private static EntityType getEntityTypeForQualifier(String qualifier) {
    return switch(qualifier) {
      case ComponentQualifiers.PROJECT -> EntityType.PROJECT_BRANCH;
      case ComponentQualifiers.VIEW -> EntityType.PORTFOLIO;
      case ComponentQualifiers.APP -> EntityType.APPLICATION;
      default -> throw new IllegalArgumentException("Unsupported component qualifier '%s'".formatted(qualifier));
    };
  }
}

View on GitHub (pinned to 184c821202)

Solutions

  1. Ensure the deletion API is only invoked with top-level project/portfolio/application components
  2. Resolve the correct service path for the component's qualifier before cleanup
  3. Add a case for the new qualifier if a new component type must support deletion
  4. Verify the component UUID passed belongs to a deletable root component

Example fix

// before
return switch(qualifier) { case PROJECT -> ...; default -> throw ...; };
// after
case ComponentQualifiers.SUBVIEW -> EntityType.PORTFOLIO;
default -> throw new IllegalArgumentException("Unsupported component qualifier '%s'".formatted(qualifier));
Defensive patterns

Strategy: validation

Validate before calling

const DELETABLE = ['TRK','VW','APP']; // PROJECT, VIEW, APP qualifiers
function isDeletableComponent(c) {
  return DELETABLE.includes(c.qualifier);
}

Try / catch

try {
  await cleaner.delete(component);
} catch (e) {
  if (e.status === 400 && /Unsupported component qualifier/.test(e.message)) {
    throw new Error(`Component ${component.key} (qualifier ${component.qualifier}) is not a project/portfolio/app`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Deleting a component whose qualifier is not PROJECT, VIEW (portfolio), or APP (application) — e.g. a module, file, or a newly introduced qualifier.

Common situations: Calling component cleanup for a sub-component UUID; plugins creating custom qualifiers; DB rows referencing components of unsupported type.

Related errors


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