passbolt/passbolt_api · error · Cake\Http\Exception\BadRequestException

The permissions identifiers must be valid UUID.

Error message

The permissions identifiers must be valid UUID.

What it means

Symmetric to the group-manager transfer, _transferContentOwners validates that every permission id in the ownership-transfer payload for solely-owned resources/folders is a valid UUID and throws BadRequestException otherwise. It fails fast before mutating any permission records.

Solutions

  1. Send the permission .id values exactly as provided in the dry-run exception body (errors.resources.sole_owner / errors.folders.sole_owner permissions)
  2. Validate each id against a UUID regex before the request
  3. Map from the permissions array, not from the resource/folder object itself
  4. Ensure the owners array is non-empty before building the payload

Example fix

// before
const owners = resources.map(r => ({ id: r.id })); // resource id, not permission id
// after
const owners = resources.flatMap(r => r.permissions.filter(p => p.type === 15).map(p => ({ id: p.id, aco_foreign_key: p.aco_foreign_key })));
Defensive patterns

Strategy: validation

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
for (const o of owners) {
  if (!UUID_RE.test(o.id)) throw new Error('permission id must be a UUID: ' + o.id);
}

Try / catch

try { await transferOwnersAndDelete(payload); } catch (e) { if (e.status === 400 && /UUID/.test(e.message)) { payload = rebuildFromDryRun(); return transferOwnersAndDelete(payload); } throw e; }

Prevention

When it happens

Trigger: Delete transfer where the owners array contains malformed ids, empty strings, or ids from the wrong model (e.g. aco_foreign_key or aro_foreign_key instead of the permission id).

Common situations: Client confusion between permission ids and resource ids when constructing the transfer; test fixtures with fake short ids; JSON copy/paste errors.

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/8c93c667535645bd. Report an issue: GitHub.

Appendix: source

Thrown at src/Controller/Users/UsersDeleteController.php:326

    /**
     * Transfer the content permissions which blocked the user delete
     *
     * @param \App\Model\Entity\User $user entity
     * @throws \Cake\Http\Exception\BadRequestException if the array of manager is
     * @return void
     */
    protected function _transferContentOwners(User $user)
    {
        $owners = $this->request->getData('transfer.owners');
        if (empty($owners)) {
            return;
        }

        $permissionsIdsToUpdate = Hash::extract($owners, '{n}.id');
        foreach ($permissionsIdsToUpdate as $id) {
            if (!Validation::uuid($id)) {
                throw new BadRequestException(__('The permissions identifiers must be valid UUID.'));
            }
        }

        $contentIdsToUpdate = Hash::extract($owners, '{n}.aco_foreign_key');
        sort($contentIdsToUpdate);

        $contentIdBlockingDelete = $this->Permissions
            ->findSharedAcosByAroIsSoleOwner(PermissionsTable::RESOURCE_ACO, $user->id, ['checkGroupsUsers' => true])
            ->all()
            ->extract('aco_foreign_key')
            ->toArray();

        if (Configure::read('passbolt.plugins.folders.enabled')) {
            $foldersIdsBlockingDelete = $this->Permissions
                ->findSharedAcosByAroIsSoleOwner(PermissionsTable::FOLDER_ACO, $user->id, ['checkGroupsUsers' => true])
                ->all()
                ->extract('aco_foreign_key')
                ->toArray();

View on GitHub (pinned to 31c1bbc10f)