{"record":{"id":"3d2cc756dc02d404","repo":"SonarSource/sonarqube","slug":"profile-s-cannot-be-deleted-because-its-descend","errorCode":null,"errorMessage":"Profile '%s' cannot be deleted because its descendant named '%s' is marked as default","messagePattern":"Profile '(.+?)' cannot be deleted because its descendant named '(.+?)' is marked as default","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java","lineNumber":106,"sourceCode":"  }\n\n  private Collection<QProfileDto> selectDescendants(DbSession dbSession, QProfileDto profile) {\n    return dbClient.qualityProfileDao().selectDescendants(dbSession, singleton(profile));\n  }\n\n  private void ensureNoneIsMarkedAsDefault(DbSession dbSession, QProfileDto profile, Collection<QProfileDto> descendants) {\n    Set<String> allUuids = new HashSet<>();\n    allUuids.add(profile.getKee());\n    descendants.forEach(p -> allUuids.add(p.getKee()));\n\n    Set<String> uuidsOfDefaultProfiles = dbClient.defaultQProfileDao().selectExistingQProfileUuids(dbSession, allUuids);\n\n    checkArgument(!uuidsOfDefaultProfiles.contains(profile.getKee()), \"Profile '%s' cannot be deleted because it is marked as default\", profile.getName());\n    descendants.stream()\n      .filter(p -> uuidsOfDefaultProfiles.contains(p.getKee()))\n      .findFirst()\n      .ifPresent(p -> {\n        throw new IllegalArgumentException(String.format(\"Profile '%s' cannot be deleted because its descendant named '%s' is marked as default\", profile.getName(), p.getName()));\n      });\n  }\n\n  private static List<QProfileDto> merge(QProfileDto profile, Collection<QProfileDto> descendants) {\n    return Stream.concat(Stream.of(profile), descendants.stream())\n      .toList();\n  }\n}\n","sourceCodeStart":88,"sourceCodeEnd":115,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java#L88-L115","documentation":"DeleteAction.ensureNoneIsMarkedAsDefault refuses to delete a quality profile when the profile itself or any of its descendant (child) profiles is marked as default. Deleting a default profile would leave the language without an active default, so the operation is rejected with this IllegalArgumentException.","triggerScenarios":"Calling api/qualityprofiles/delete for a profile whose kee is in uuidsOfDefaultProfiles, or for a profile that has at least one child profile (built from it) that is the default profile for its language.","commonSituations":"Bulk cleanup scripts deleting profiles without checking which ones are default; deleting a parent profile after a team copied it and made the copy the default; automation that assumes non-default parents can always be removed.","solutions":["Query api/qualityprofiles/search and mark another profile as default (api/qualityprofiles/set_default) for the affected language","Delete the descendant default profile first, or unset its default flag, then delete the target profile","Adjust automation to skip or handle profiles listed as default in the search response"],"exampleFix":"// before\ncurl -X POST api/qualityprofiles/delete?language=java&qualityProfile=MyProfile\n// after\ncurl -X POST api/qualityprofiles/set_default?id=AXSonar_way\nsleep 1\ncurl -X POST api/qualityprofiles/delete?language=java&qualityProfile=MyProfile","handlingStrategy":"validation","validationCode":"// before deleting, check profile and descendants for default flags\nconst profiles = await get(\"api/qualityprofiles/search?language=\" + lang);\nconst target = profiles.profiles.find(p => p.key === key);\nconst blockers = profiles.profiles.filter(p => p.name === target.name || p.parentName === target.name).filter(p => p.isDefault);\nif (blockers.length > 0) await post(\"api/qualityprofiles/set_default\", { id: fallbackProfileKey });","typeGuard":"boolean isSafeToDelete(QProfileSummary p) {\n  return !p.isDefault;\n}","tryCatchPattern":"try {\n  post(\"api/qualityprofiles/delete\", { key });\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"is marked as default\")) {\n    setAnotherProfileAsDefaultForSameLanguage();\n  }\n}","preventionTips":["Always call api/qualityprofiles/search and check isDefault before deleting","Unset the default flag on parent and child profiles first","In bulk-delete scripts, resolve descendants (api/qualityprofiles/children) beforehand"],"tags":["sonarqube","quality-profile","default-profile","delete-guard"],"backgroundTag":"invalid-state-transition","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}