passbolt/passbolt_api · error · BadRequestException

The identifier should be a valid UUID.

Error message

The identifier should be a valid UUID.

What it means

findAllByAro() in PermissionsFindersTrait validates that the $aroForeignKey argument is a valid UUID and throws BadRequestException otherwise. All permission-finder methods built on it (findHighestByAcoAndAro, findAcosAccessesDiffBetweenGroupAndUser, findAcosByAroIsOwner) inherit this check, since a non-UUID ARO id would produce a broken or dangerous SQL comparison.

Solutions

  1. Ensure the aro id passed in is a valid UUID as stored in users.id/groups.id.
  2. Validate route/query parameters with Cake\Validation::uuid() in the controller before calling the finder.
  3. Fix upstream callers that build the id from untrusted input (add parameter validation).
  4. If ids come from an external system, map legacy integer ids to passbolt UUIDs first.

Example fix

// before
$perms = $this->Permissions->findHighestByAcoAndAro($aco, $userIdFromRequest);
// after
use Cake\Validation\Validation;
if (!Validation::uuid($userIdFromRequest)) {
    throw new BadRequestException('The identifier should be a valid UUID.');
}
$perms = $this->Permissions->findHighestByAcoAndAro($aco, $userIdFromRequest);
Defensive patterns

Strategy: type-guard

Validate before calling

use Cake\Validation\Validation; if (!Validation::uuid($aroForeignKey)) { throw new Cake\Http\Exception\BadRequestException('aroForeignKey must be a UUID'); }

Type guard

function isUuidString(mixed $v): bool { return is_string($v) && Cake\Validation\Validation::uuid($v); }

Try / catch

try { $perms = $this->Permissions->findHighestByAcoAndAro($aco, $aroId); } catch (\Cake\Http\Exception\BadRequestException $e) { // return 400: invalid identifier }

Prevention

When it happens

Trigger: Calling any of the permission finders (or the controller endpoints that use them, e.g. permission lookups for a resource) with a user/group id that is null-coerced to '', a slug, an integer id, or otherwise malformed instead of a 36-char UUID.

Common situations: Route parameters picked up from a mistyped URL (e.g. /permissions/user/not-a-uuid); legacy integrations sending integer ids; unvalidated user input passed straight into the query; tests using placeholder ids like '1' or 'abc'.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at src/Model/Traits/Permissions/PermissionsFindersTrait.php:106

    /**
     * Returns a query retrieving the permissions an aro have.
     *
     * The $checkGroupsUsers will also return the permissions inherited from the groups the aro is member of.
     *
     * @param string $acoType The aco type. By instance Resource or Folder.
     * @param string $aroForeignKey The target aro id. By instance a user or a group id.
     * @param array|null $options options
     * [
     *   bool $checkGroupsUsers Check also for the groups the aro is member of
     * ]
     * @return \Cake\ORM\Query\SelectQuery
     * @throws \Cake\Http\Exception\BadRequestException if the aro foreign key is not a valid UUID
     */
    public function findAllByAro(string $acoType, string $aroForeignKey, ?array $options = []): SelectQuery
    {
        if (!Validation::uuid($aroForeignKey)) {
            throw new BadRequestException(__('The identifier should be a valid UUID.'));
        }
        $checkGroupsUsers = Hash::get($options, 'checkGroupsUsers', false);

        // Retrieve also the permissions for the groups a user is member of.
        if ($checkGroupsUsers) {
            $aroForeignKeys = $this->Groups->GroupsUsers->find()
                ->select('group_id')
                ->where(['user_id' => $aroForeignKey])
                ->epilog('UNION SELECT :aroForeignKey')
                ->bind(':aroForeignKey', $aroForeignKey);
        } else {
            $aroForeignKeys = [$aroForeignKey];
        }

        return $this->find()
            ->where([
                'Permissions.aco' => $acoType,
                'Permissions.aro_foreign_key IN' => $aroForeignKeys,

View on GitHub (pinned to 31c1bbc10f)