{"record":{"id":"f4bf00ee137cd48a","repo":"SonarSource/sonarqube","slug":"provided-user-with-login-s-does-not-have-brows","errorCode":null,"errorMessage":"Provided user with login '%s' does not have 'Browse' permission to project","messagePattern":"Provided user with login '(.+?)' does not have 'Browse' permission to project","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/AssignAction.java","lineNumber":158,"sourceCode":"    }\n  }\n\n  private static void checkHotspotStatusAndResolution(IssueDto hotspotDto) {\n    if (!STATUS_TO_REVIEW.equals(hotspotDto.getStatus()) && !RESOLUTION_ACKNOWLEDGED.equals(hotspotDto.getResolution())) {\n      throw new IllegalArgumentException(\"Cannot change the assignee of this hotspot given its current status and resolution\");\n    }\n  }\n\n  private UserDto getAssignee(DbSession dbSession, String assignee) {\n    return checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, assignee), \"Unknown user: %s\", assignee);\n  }\n\n  private void checkAssigneeProjectPermission(DbSession dbSession, UserDto assignee, String issueBranchUuid) {\n    ProjectDto project = checkFoundWithOptional(dbClient.projectDao().selectByBranchUuid(dbSession, issueBranchUuid),\n      \"Could not find branch for issue\");\n\n    if (project.isPrivate() && !hasProjectPermission(dbSession, assignee.getUuid(), project.getUuid())) {\n      throw new IllegalArgumentException(String.format(\"Provided user with login '%s' does not have 'Browse' permission to project\", assignee.getLogin()));\n    }\n  }\n\n  private boolean hasProjectPermission(DbSession dbSession, String userUuid, String projectUuid) {\n    return dbClient.authorizationDao().selectEntityPermissions(dbSession, projectUuid, userUuid).contains(ProjectPermission.USER.getKey());\n  }\n\n  private static HotspotChangedEvent buildEventData(DefaultIssue defaultIssue, @Nullable UserDto assignee, String filePath) {\n    return new HotspotChangedEvent.Builder()\n      .setKey(defaultIssue.key())\n      .setProjectKey(defaultIssue.projectKey())\n      .setStatus(defaultIssue.status())\n      .setResolution(defaultIssue.resolution())\n      .setUpdateDate(defaultIssue.updateDate())\n      .setAssignee(assignee == null ? null : assignee.getLogin())\n      .setFilePath(filePath)\n      .build();\n  }","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/AssignAction.java#L140-L176","documentation":"Thrown by the assign action of the Security Hotspots web service when the user chosen as assignee cannot see the project the hotspot belongs to. For private projects, SonarQube requires that any assignable user holds the 'Browse' (USER) permission on the project. The server rejects the assignment rather than silently granting visibility.","triggerScenarios":"Calling POST api/hotspots/assign with an 'assign' login whose user is not in the project's USER permission list while the project is private. The check only runs for private projects, so public projects never hit it.","commonSituations":"Assigning a hotspot to an admin or bot account that was never granted project access; assigning to a user of another organization; project visibility switched to private after users were assigned previously; automated scripts using a service account without Browse permission.","solutions":["Grant the assignee the 'User' (Browse) permission on the project in Project Settings > Permissions","Check the user has access via GET api/permissions/users with projectKey before assigning","Assign to a different user who already has Browse permission","If the project should be public, change visibility in Project Settings so the check is skipped"],"exampleFix":"// before\ncurl -X POST '.../api/hotspots/assign?hotspot=AX1&assign=ci-bot'\n// after\n# grant permission first, then assign\ncurl -X POST '.../api/permissions/add_user?projectKey=my_project&login=ci-bot&permission=user'\ncurl -X POST '.../api/hotspots/assign?hotspot=AX1&assign=ci-bot'","handlingStrategy":"validation","validationCode":"const perms = await get('/api/permissions/users', {projectKey, login: assigneeLogin, permission: 'user'});\nif (!perms.permissions.some(p => p.login === assigneeLogin)) throw new Error('assignee lacks Browse permission');","typeGuard":null,"tryCatchPattern":"try { await post('/api/hotspots/assign', {hotspot, assign: login}); } catch (e) { if (e.status === 400 && e.message.includes(\"does not have 'Browse'\")) { /* grant permission or pick another user */ } else throw e; }","preventionTips":["Check assignee's project permissions before any automated assignment","Maintain a list of assignable users synced with project permissions","Avoid assigning to service/bot accounts lacking Browse access"],"tags":["sonarqube","permissions","hotspots","webapi"],"backgroundTag":"permission-denied","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"}