passbolt/passbolt_api · error · NotFoundException

The role does not exist or deleted.

Error message

The role does not exist or deleted.

What it means

RolesUpdateService::getRole throws this NotFoundException when no non-deleted role exists for the given ID (firstOrFail on the notDeleted finder raises RecordNotFoundException). It is surfaced as a 404 to the PUT /roles/{id} caller.

Solutions

  1. Confirm the role exists with GET /roles and use its current ID.
  2. If the role was soft-deleted, recreate it via POST /roles instead of updating.
  3. Invalidate/refetch any cached role listings in the client.
  4. Verify the UUID is copied correctly (no truncation or encoding issues).

Example fix

// before
PUT /roles/<deleted-role-id> -> 404 The role does not exist or deleted
// after
GET /roles  # pick valid id
PUT /roles/<valid-id> {"name": "new-name"} -> 200
Defensive patterns

Strategy: try-catch

Validate before calling

const roles = await api.listRoles();
if (!roles.some(r => r.id === roleId)) {
  throw new Error('Cannot update: role ' + roleId + ' does not exist');
}

Type guard

function isUpdatableRole(roles, id) {
  return Array.isArray(roles) && roles.some(r => r && r.id === id);
}

Try / catch

try {
  await api.updateRole(roleId, payload);
} catch (e) {
  if (e.status === 404 && /does not exist or deleted/i.test(e.message)) {
    // refetch roles; recreate the role if it was soft-deleted
  } else throw e;
}

Prevention

When it happens

Trigger: PUT /roles/{uuid} where the UUID does not match any role, or matches a role already soft-deleted.

Common situations: Updating a role that was deleted in another session/tab, stale role ID from a cached list, double-submission after the first update deleted it, or a typo'd UUID.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/06fe24229d7b4f51. Report an issue: GitHub.

Appendix: source

Thrown at src/Service/Roles/RolesUpdateService.php:96

            'role' => $result,
            'oldName' => $oldName,
        ]);

        return $result;
    }

    /**
     * @param string $roleId Role identifier to get.
     * @return \App\Model\Entity\Role
     * @throws \Cake\Http\Exception\NotFoundException If role doesn't exist in the database
     */
    private function getRole(string $roleId): Role
    {
        try {
            /** @var \App\Model\Entity\Role $role */
            $role = $this->Roles->find('notDeleted')->where(['id' => $roleId])->firstOrFail();
        } catch (RecordNotFoundException $e) {
            throw new NotFoundException(__('The role does not exist or deleted.'), null, $e);
        }

        return $role;
    }

    /**
     * @param \App\Model\Entity\Role $role Role entity.
     * @param array $data Data to patch.
     * @param \App\Utility\UserAccessControl $uac User Access Control.
     * @return \App\Model\Entity\Role
     */
    private function patchRoleEntity(Role $role, array $data, UserAccessControl $uac): Role
    {
        $name = Hash::get($data, 'name', '');

        $data = [
            'name' => $name,
            'modified_by' => $uac->getId(),

View on GitHub (pinned to 31c1bbc10f)