passbolt/passbolt_api · error · InternalErrorException
No user found for the personal tag id
Error message
No user found for the personal tag id: "{0}". What it means
Personal tags in V5 must be encrypted for the owning user. migratePersonal expects the tag's 'users' contains to carry at least one user; when the association is empty it throws InternalErrorException naming the tag id. This indicates inconsistent data — a personal tag with no owning user.
Solutions
- Add contain('Users') (or the required containment) to the query that fetches tags for migration.
- Clean up orphaned personal tags (delete tags with no tag records) before migrating.
- Re-associate an owner or delete the dangling tag, then rerun migration.
- Audit with SQL: select tags without matching tag_records/users rows.
Example fix
// before $tags = $this->Tags->find()->all(); // after $tags = $this->Tags->find()->contain(['Users'])->where(['Tags.is_shared' => false])->all();
Defensive patterns
Strategy: validation
Validate before calling
$orphanTags = $tagsTable->find()
->contain(['Users'])
->where(['is_shared' => false])
->all()
->filter(fn($t) => count($t->get('users') ?? []) === 0); Type guard
function hasOwner(?Tag $tag): bool {
$users = $tag?->get('users');
return is_array($users) && count($users) > 0 && $users[0] !== null;
} Try / catch
try {
$service->migrate($uac, $batch);
} catch (InternalErrorException $e) {
if (str_contains($e->getMessage(), 'No user found for the personal tag')) {
$this->log('Orphaned tag; exclude from batch and clean up');
} else { throw $e; }
} Prevention
- Always contain('Users') on personal-tag migration queries
- Clean orphaned tags after user deletion
- Audit tag_records foreign keys periodically
- Skip-and-log bad rows instead of aborting whole batch
When it happens
Trigger: Migrating a personal (non-shared) tag whose _tag_records/users join data is missing or the containment was not applied on the query feeding the migration.
Common situations: Orphaned tags left by deleted users without cleanup; migration batch query missing ->contain('Users'); partially deleted resource-tag relations from older versions.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- User contain data missing for the tag id
- No OpenPGP key found for the user. The metadata could not…
- No permission found for folder ID
- Tag creation with cleartext metadata not allowed.
- Tag ID " " is already V5
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/a6a2f1a5ca5f47b7.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Tags/src/Service/Metadata/MigrateAllV4TagsToV5Service.php:200
'metadata' => $metadataEncrypted,
'metadata_key_id' => $metadataKey->id,
'metadata_key_type' => MetadataKey::TYPE_SHARED_KEY,
'is_shared' => true,
]);
}
/**
* @param \Passbolt\Tags\Model\Dto\MetadataTagDto $dto DTO.
* @param \Passbolt\Tags\Model\Entity\Tag $tag Tag entity.
* @return void
*/
private function migratePersonal(MetadataTagDto $dto, Tag $tag): void
{
$metadataArray = $dto->getClearTextMetadata();
$users = $tag->get('users');
if (!is_array($users) || count($users) < 1) {
throw new InternalErrorException(__('No user found for the personal tag id: "{0}".', $tag->id));
}
/** @var \App\Model\Entity\User $user */
$user = $users[0];
if (is_null($user)) {
throw new InternalErrorException(__('User contain data missing for the tag id: "{0}".', $tag->id));
}
if (is_null($user->gpgkey)) {
$msg = __('No OpenPGP key found for the user.') . ' ';
$msg .= __('The metadata could not be encrypted with the user id: {0}.', $user->id);
throw new InternalErrorException($msg);
}
try {
$gpg = OpenPGPBackendFactory::get();
$gpg->clearKeys();
$gpg = $this->setSignKeyWithServerKey($gpg);
$gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey);View on GitHub (pinned to 31c1bbc10f)