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
- Ensure the deletion API is only invoked with top-level project/portfolio/application components
- Resolve the correct service path for the component's qualifier before cleanup
- Add a case for the new qualifier if a new component type must support deletion
- 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
- Only pass root components (project/portfolio/application) to deletion APIs
- Read 'qualifier' from api/components/show before cleanup
- Skip FILE/DIRECTORY/MODULE qualifiers in bulk jobs
- Update mappings when new component types are introduced
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
- %s key '%s' not found
- Component '%s' on branch '%s' not found
- Component '%s' of pull request '%s' not found
- %s is not a valid url
- Error while executing a call to %s. Return code %s. Error me
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/a3c18c01d7e95b7c.
Report an issue: GitHub.