SonarSource/sonarqube · error · IllegalArgumentException

Component is not a top level entity

Error message

Component  is not a top level entity

What it means

ComponentUpdater.createWithoutCommit can only create top-level entities: projects (or portfolios). If the ComponentDto it is asked to persist is neither a project nor a portfolio (e.g. a directory/file module), it throws this IllegalArgumentException. ComponentDto.toString includes a leading space, which is why the message shows 'Component is not...'.

Solutions

  1. Only pass projects (TRK) or portfolios (PORTFOLIO) to the creation endpoint/service
  2. Create directories/files through analysis report processing, not the component creation API
  3. Log the component qualifier before the call to detect wrong qualifier values

Example fix

// before
new ComponentDto().setKey("my:app:src").setQualifier("BRC") // branch-like qualifier
// after
new ComponentDto().setKey("my:app").setQualifier("TRK").setBranchUuid(...) // top-level project
Defensive patterns

Strategy: validation

Validate before calling

if (!"TRK".equals(componentDto.getQualifier()) && !"PORTFOLIO".equals(componentDto.getQualifier())) {
  throw new IllegalArgumentException("Only top-level projects/portfolios can be created here, got: " + componentDto.getQualifier());
}

Type guard

boolean isTopLevel(ComponentDto c) {
  String q = c != null ? c.getQualifier() : null;
  return "TRK".equals(q) || "PORTFOLIO".equals(q);
}

Try / catch

try {
  updater.createWithoutCommit(dbSession, component, params);
} catch (IllegalArgumentException e) {
  log.error("Refusing non-top-level component: {}", component, e);
  throw e; // caller bug: wrong qualifier — do not retry
}

Prevention

When it happens

Trigger: Invoking the component creation path (e.g. api/components/create or internal provisioning) with a component qualifier other than TRK/PORTFOLIO — for instance attempting to create a BRC/DIR/FIL component as a root entity.

Common situations: Calling POST api/components/create with a non-project qualifier; automated importers building component trees top-down and passing child components to the top-level creation API; plugin/webhook code reusing createWithoutCommit for views/sub-views.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at server/sonar-webserver-common/src/main/java/org/sonar/server/common/component/ComponentUpdater.java:150

    PortfolioDto portfolioDto = null;

    if (isProjectOrApp(componentDto)) {
      var isAiCodeFixEnabled = isAiCodeFixEnabledForAllProjects();
      projectDto = toProjectDto(componentDto, now, componentCreationParameters.creationMethod(), isAiCodeFixEnabled);
      dbClient.projectDao().insert(dbSession, projectDto);
      addToFavourites(dbSession, projectDto, componentCreationParameters.userUuid(), componentCreationParameters.userLogin());
      mainBranch = createMainBranch(dbSession, componentDto.uuid(), projectDto.getUuid(), componentCreationParameters.mainBranchName());
      if (componentCreationParameters.isManaged()) {
        applyPublicPermissionsForCreator(dbSession, projectDto, componentCreationParameters.userUuid());
      } else {
        permissionTemplateService.applyDefaultToNewComponent(dbSession, projectDto, componentCreationParameters.userUuid());
      }
    } else if (isPortfolio(componentDto)) {
      portfolioDto = toPortfolioDto(componentDto, now);
      dbClient.portfolioDao().insert(dbSession, portfolioDto, false);
      permissionTemplateService.applyDefaultToNewComponent(dbSession, portfolioDto, componentCreationParameters.userUuid());
    } else {
      throw new IllegalArgumentException("Component " + componentDto + " is not a top level entity");
    }

    return new ComponentCreationData(componentDto, portfolioDto, mainBranch, projectDto);
  }

  private boolean isAiCodeFixEnabledForAllProjects() {
    return Optional.ofNullable(dbClient.propertiesDao().selectGlobalProperty(SUGGESTION_FEATURE_ENABLED_PROPERTY))
      .map(PropertyDto::getValue)
      .stream().anyMatch(ENABLED_FOR_ALL_PROJECTS::equals);
  }

  private void applyPublicPermissionsForCreator(DbSession dbSession, ProjectDto projectDto, @Nullable String userUuid) {
    if (userUuid != null) {
      UserDto userDto = dbClient.userDao().selectByUuid(dbSession, userUuid);
      checkState(userDto != null, "User with uuid '%s' doesn't exist", userUuid);
      userPermissionUpdater.apply(dbSession,
        PUBLIC_PERMISSIONS.stream()
        .map(permission -> toUserPermissionChange(permission, projectDto, userDto))

View on GitHub (pinned to 184c821202)