{"record":{"id":"c45e32ce975f89c3","repo":"passbolt/passbolt_api","slug":"no-permission-found-for-resource-id-0","errorCode":null,"errorMessage":"No permission found for resource ID {0}","messagePattern":"No permission found for resource ID (.+?)","errorType":"exception","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php","lineNumber":112,"sourceCode":"            ->toArray();\n\n        if (empty($resources)) {\n            $this->addError(['error_message' => __('No resources to migrate.')]);\n\n            return $this->getResult();\n        }\n\n        foreach ($resources as $resource) {\n            $dto = MetadataResourceDto::fromArray($resource->toArray());\n\n            try {\n                if ($dto->isV5()) {\n                    $msg = __('Resource ID \"{0}\" is already V5', $resource->id);\n                    throw new InternalErrorException($msg);\n                }\n                if (count($resource->permissions) === 0) {\n                    $msg = __('No permission found for resource ID {0}', $resource->id);\n                    throw new InternalErrorException($msg);\n                }\n                if (count($resource->permissions) === 1 && !$resource->permissions[0]->isAroGroup()) {\n                    $this->migratePersonal($dto, $resource);\n                } else {\n                    $this->migrateShared($dto, $resource);\n                }\n                $this->addMigrated($resource);\n            } catch (Exception $e) {\n                // Continue with next resource if any error\n                $error = ['resource_id' => $resource->id, 'error_message' => $e->getMessage()];\n                if (Configure::read('debug')) {\n                    $error['trace'] = $e->getTraceAsString();\n                }\n                $this->addError($error);\n            }\n        }\n\n        return $this->getResult();","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php#L94-L130","documentation":"Thrown in migrate() when a V4 resource has zero associated permissions. Personal-resource metadata encryption needs at least an owner permission to determine the encrypting user key; a permissionless resource cannot be migrated. The resource is skipped and the error recorded in the migration result.","triggerScenarios":"Running migrate() when the resources table contains a V4 resource (matching one of the four V4 resource type IDs) whose permissions set is empty — e.g. its sole owner was hard-deleted along with the permission, or permissions rows were removed manually or by a cleanup script.","commonSituations":"Legacy instances where users were deleted without reassigning their resources; database restores that dropped permission rows; orphaned resources left by earlier passbolt versions' cleanup bugs.","solutions":["Assign a valid owner permission to the resource for an existing active user (insert into permissions with type OWNER/15), then re-run migration.","If the resource is unwanted orphan data, delete it, then re-run migration.","Audit V4 resources without permissions via a SQL query joining permissions before running migration.","Re-run migration; only flagged resources fail, others migrate."],"exampleFix":"// before: orphaned resource with no permissions\n// after: give it an owner\nINSERT INTO permissions (id, aco, aco_foreign_key, aro, aro_foreign_key, type, created, modified)\nVALUES (UUID(), 'App.Model.Resource', '<resource-id>', 'User', '<active-user-id>', 15, NOW(), NOW());","handlingStrategy":"validation","validationCode":"// before migrating, find V4 resources without permissions\n$orphans = $resourcesTable->find('all')\n    ->leftJoinWith('Permissions')\n    ->where(['resource_type_id IN' => $v4TypeIds, 'Permissions.id IS' => null])\n    ->all();","typeGuard":"if ($resource->permissions === null || count($resource->permissions) === 0) { skip($resource); }","tryCatchPattern":null,"preventionTips":["Reassign or remove orphaned resources when deleting users.","Enable referential checks/cleanup scripts that flag permissionless resources.","Audit permissions before running bulk migrations.","Keep soft-delete on users so ownership can be recovered."],"tags":["migration","metadata","permissions","orphaned-data"],"backgroundTag":"empty-required-field","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"}