passbolt/passbolt_api · error · InternalErrorException
No permission found for resource ID
Error message
No permission found for resource ID {0} What it means
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.
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.
Example fix
// before: orphaned resource with no permissions // after: give it an owner INSERT INTO permissions (id, aco, aco_foreign_key, aro, aro_foreign_key, type, created, modified) VALUES (UUID(), 'App.Model.Resource', '<resource-id>', 'User', '<active-user-id>', 15, NOW(), NOW());
Defensive patterns
Strategy: validation
Validate before calling
// before migrating, find V4 resources without permissions
$orphans = $resourcesTable->find('all')
->leftJoinWith('Permissions')
->where(['resource_type_id IN' => $v4TypeIds, 'Permissions.id IS' => null])
->all(); Type guard
if ($resource->permissions === null || count($resource->permissions) === 0) { skip($resource); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- No user provided. The metadata could not be encrypted for…
- The metadata could not be encrypted with the user id: .
- Folder creation with cleartext metadata not allowed.
- Folder ID " " is already V5
- No OpenPGP key found for the user. The metadata could not…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/c45e32ce975f89c3.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php:112
->toArray();
if (empty($resources)) {
$this->addError(['error_message' => __('No resources to migrate.')]);
return $this->getResult();
}
foreach ($resources as $resource) {
$dto = MetadataResourceDto::fromArray($resource->toArray());
try {
if ($dto->isV5()) {
$msg = __('Resource ID "{0}" is already V5', $resource->id);
throw new InternalErrorException($msg);
}
if (count($resource->permissions) === 0) {
$msg = __('No permission found for resource ID {0}', $resource->id);
throw new InternalErrorException($msg);
}
if (count($resource->permissions) === 1 && !$resource->permissions[0]->isAroGroup()) {
$this->migratePersonal($dto, $resource);
} else {
$this->migrateShared($dto, $resource);
}
$this->addMigrated($resource);
} catch (Exception $e) {
// Continue with next resource if any error
$error = ['resource_id' => $resource->id, 'error_message' => $e->getMessage()];
if (Configure::read('debug')) {
$error['trace'] = $e->getTraceAsString();
}
$this->addError($error);
}
}
return $this->getResult();View on GitHub (pinned to 31c1bbc10f)