SonarSource/sonarqube · error · NotFoundException

Entity not found

Error message

Entity not found

What it means

PermissionWsSupport.findEntity resolves an entity (project/view) by uuid or key for permission WebServices. It throws NotFoundException when no EntityDto matches, or when the entity exists but is a SUBVIEW qualifier (sub-views are not valid permission entities).

Source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/PermissionWsSupport.java:86

    this.configuration = configuration;
    this.groupWsSupport = groupWsSupport;
  }

  public void checkPermissionManagementAccess(UserSession userSession, @Nullable EntityDto entity) {
    checkProjectAdmin(userSession, configuration, entity);
  }

  @CheckForNull
  public EntityDto findEntity(DbSession dbSession, Request request) {
    String uuid = request.param(PermissionsWsParameters.PARAM_PROJECT_ID);
    String key = request.param(PermissionsWsParameters.PARAM_PROJECT_KEY);
    if (uuid != null || key != null) {
      ProjectWsRef.validateUuidAndKeyPair(uuid, key);
      Optional<EntityDto> entityDto = uuid != null ? dbClient.entityDao().selectByUuid(dbSession, uuid) : dbClient.entityDao().selectByKey(dbSession, key);
      if (entityDto.isPresent() && !ComponentQualifiers.SUBVIEW.equals(entityDto.get().getQualifier())) {
        return entityDto.get();
      } else {
        throw new NotFoundException("Entity not found");
      }
    }
    return null;
  }

  public GroupUuidOrAnyone findGroupUuidOrAnyone(DbSession dbSession, Request request) {
    String groupName = request.mandatoryParam(PARAM_GROUP_NAME);
    return groupWsSupport.findGroupOrAnyone(dbSession, groupName);
  }

  @CheckForNull
  public GroupDto findGroupDtoOrNullIfAnyone(DbSession dbSession, Request request) {
    String groupName = request.mandatoryParam(PARAM_GROUP_NAME);
    return groupWsSupport.findGroupDtoOrNullIfAnyone(dbSession, groupName);
  }

  public UserId findUser(DbSession dbSession, String login) {
    UserDto dto = ofNullable(dbClient.userDao().selectActiveUserByLogin(dbSession, login))

View on GitHub (pinned to 184c821202)

Solutions

  1. Verify the project key exists via GET api/projects/search?q=<key> or GET api/components/show?component=<key>
  2. Use the project's uuid (project/id) instead of the key, or vice versa, matching the current entity
  3. If targeting a view, use the top-level view key, not a sub-view qualifier
  4. Re-sync keys after project rename/move; the key changes when the project is moved between portfolios

Example fix

// before: possibly stale key
const entity = await client.permissions.addUser({ key: oldKey, login: 'john' });

// after: resolve the current key first
const { components } = await client.projects.search({ q: projectName });
await client.permissions.addUser({ key: components[0].key, login: 'john' });
Defensive patterns

Strategy: validation

Validate before calling

const res = await get(`/api/components/show?component=${encodeURIComponent(key)}`).catch(() => null);
if (!res || res.component.qualifier === 'SVW') throw new Error(`invalid entity: ${key}`);

Type guard

function isValidEntityKey(key) { return typeof key === 'string' && /^[A-Za-z0-9_.:\-]+$/.test(key); }

Try / catch

try { await client.permissions.addUser({ key, login }); } catch (e) { if (e.status === 404 && e.message.includes('Entity not found')) { /* verify key via projects/search */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling permission WS endpoints (e.g. api/permissions/add_user, api/permissions/groups) with a project/id or project/key that does not exist, references a deleted project, or points to a sub-view qualifier.

Common situations: Typos in project key; project was deleted or renamed (key changed); automation scripts using stale IDs; referencing a sub-view of an application/portfolio view which is not a permission target.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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