{"record":{"id":"8c93c667535645bd","repo":"passbolt/passbolt_api","slug":"the-permissions-identifiers-must-be-valid-uuid-8c93c6","errorCode":null,"errorMessage":"The permissions identifiers must be valid UUID.","messagePattern":"The permissions identifiers must be valid UUID\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Controller/Users/UsersDeleteController.php","lineNumber":326,"sourceCode":"\n    /**\n     * Transfer the content permissions which blocked the user delete\n     *\n     * @param \\App\\Model\\Entity\\User $user entity\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the array of manager is\n     * @return void\n     */\n    protected function _transferContentOwners(User $user)\n    {\n        $owners = $this->request->getData('transfer.owners');\n        if (empty($owners)) {\n            return;\n        }\n\n        $permissionsIdsToUpdate = Hash::extract($owners, '{n}.id');\n        foreach ($permissionsIdsToUpdate as $id) {\n            if (!Validation::uuid($id)) {\n                throw new BadRequestException(__('The permissions identifiers must be valid UUID.'));\n            }\n        }\n\n        $contentIdsToUpdate = Hash::extract($owners, '{n}.aco_foreign_key');\n        sort($contentIdsToUpdate);\n\n        $contentIdBlockingDelete = $this->Permissions\n            ->findSharedAcosByAroIsSoleOwner(PermissionsTable::RESOURCE_ACO, $user->id, ['checkGroupsUsers' => true])\n            ->all()\n            ->extract('aco_foreign_key')\n            ->toArray();\n\n        if (Configure::read('passbolt.plugins.folders.enabled')) {\n            $foldersIdsBlockingDelete = $this->Permissions\n                ->findSharedAcosByAroIsSoleOwner(PermissionsTable::FOLDER_ACO, $user->id, ['checkGroupsUsers' => true])\n                ->all()\n                ->extract('aco_foreign_key')\n                ->toArray();","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Users/UsersDeleteController.php#L308-L344","documentation":"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.","triggerScenarios":"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).","commonSituations":"Client confusion between permission ids and resource ids when constructing the transfer; test fixtures with fake short ids; JSON copy/paste errors.","solutions":["Send the permission .id values exactly as provided in the dry-run exception body (errors.resources.sole_owner / errors.folders.sole_owner permissions)","Validate each id against a UUID regex before the request","Map from the permissions array, not from the resource/folder object itself","Ensure the owners array is non-empty before building the payload"],"exampleFix":"// before\nconst owners = resources.map(r => ({ id: r.id })); // resource id, not permission id\n// after\nconst owners = resources.flatMap(r => r.permissions.filter(p => p.type === 15).map(p => ({ id: p.id, aco_foreign_key: p.aco_foreign_key })));","handlingStrategy":"validation","validationCode":"const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nfor (const o of owners) {\n  if (!UUID_RE.test(o.id)) throw new Error('permission id must be a UUID: ' + o.id);\n}","typeGuard":null,"tryCatchPattern":"try { await transferOwnersAndDelete(payload); } catch (e) { if (e.status === 400 && /UUID/.test(e.message)) { payload = rebuildFromDryRun(); return transferOwnersAndDelete(payload); } throw e; }","preventionTips":["Use permission ids from the dry-run body's permissions arrays, not resource ids","Validate id format client-side before each transfer call","Distinguish permission.id from aco_foreign_key in your client models"],"tags":["validation","uuid","permissions"],"backgroundTag":"invalid-identifier-format","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}