{"record":{"id":"a3c18c01d7e95b7c","repo":"SonarSource/sonarqube","slug":"unsupported-component-qualifier-s","errorCode":null,"errorMessage":"Unsupported component qualifier '%s'","messagePattern":"Unsupported component qualifier '(.+?)'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java","lineNumber":112,"sourceCode":"    dbClient.userDao().cleanHomepage(dbSession, entity);\n    if (ComponentQualifiers.PROJECT.equals(entity.getQualifier())) {\n      dbClient.userTokenDao().deleteByProjectUuid(dbSession, entity.getKey(), entity.getUuid());\n    }\n    // Note that we do not send an event for each individual branch being deleted with the project\n    indexers.commitAndIndexEntities(dbSession, singletonList(entity), EntityEvent.DELETION);\n  }\n\n  private void deleteHistoryForEntity(DbSession dbSession, String entityId, EntityType entityType) {\n    issueCountHistoryRepository.deleteHistoryForEntity(dbSession, entityId, entityType);\n    measureHistoryRepository.deleteHistoryForEntity(dbSession, entityId, entityType);\n  }\n\n  private static EntityType getEntityTypeForQualifier(String qualifier) {\n    return switch(qualifier) {\n      case ComponentQualifiers.PROJECT -> EntityType.PROJECT_BRANCH;\n      case ComponentQualifiers.VIEW -> EntityType.PORTFOLIO;\n      case ComponentQualifiers.APP -> EntityType.APPLICATION;\n      default -> throw new IllegalArgumentException(\"Unsupported component qualifier '%s'\".formatted(qualifier));\n    };\n  }\n}\n","sourceCodeStart":94,"sourceCodeEnd":116,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java#L94-L116","documentation":"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.","triggerScenarios":"Deleting a component whose qualifier is not PROJECT, VIEW (portfolio), or APP (application) — e.g. a module, file, or a newly introduced qualifier.","commonSituations":"Calling component cleanup for a sub-component UUID; plugins creating custom qualifiers; DB rows referencing components of unsupported type.","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"],"exampleFix":"// before\nreturn switch(qualifier) { case PROJECT -> ...; default -> throw ...; };\n// after\ncase ComponentQualifiers.SUBVIEW -> EntityType.PORTFOLIO;\ndefault -> throw new IllegalArgumentException(\"Unsupported component qualifier '%s'\".formatted(qualifier));","handlingStrategy":"validation","validationCode":"const DELETABLE = ['TRK','VW','APP']; // PROJECT, VIEW, APP qualifiers\nfunction isDeletableComponent(c) {\n  return DELETABLE.includes(c.qualifier);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await cleaner.delete(component);\n} catch (e) {\n  if (e.status === 400 && /Unsupported component qualifier/.test(e.message)) {\n    throw new Error(`Component ${component.key} (qualifier ${component.qualifier}) is not a project/portfolio/app`);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["java","components","deletion"],"backgroundTag":"unsupported-enum-value","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"}