passbolt/passbolt_api · error · InternalErrorException
User contain data missing for the tag id
Error message
User contain data missing for the tag id: "{0}". What it means
After fetching the owning user for a personal tag, migratePersonal checks that users[0] is not null before using it. A null entry means the contained user data is missing despite the association row count check passing, so an InternalErrorException naming the tag id is thrown.
Solutions
- Filter out tags whose contained user row no longer exists before migration.
- Repair referential integrity: delete tag records pointing at missing users.
- Verify the containment configuration for the migration query.
- Skip-and-log this tag per-tag and continue the batch, then remediate manually.
Example fix
// before
$user = $users[0];
// after
$user = $users[0] ?? null;
if ($user === null) { $this->skipped[] = $tag->id; return; } Defensive patterns
Strategy: type-guard
Validate before calling
foreach ($tags as $tag) {
$users = $tag->get('users');
if (!is_array($users) || !isset($users[0])) { $skip[] = $tag->id; }
} Type guard
function firstUser(?array $users): ?User {
return (isset($users[0]) && $users[0] instanceof User) ? $users[0] : null;
} Try / catch
try {
$service->migrate($uac, $batch);
} catch (InternalErrorException $e) {
if (str_contains($e->getMessage(), 'User contain data missing')) {
$this->log('Null contained user; repair joins for tag');
} else { throw $e; }
} Prevention
- Guard contained associations with instanceof checks
- Verify joins point at existing user rows before migrating
- Use inner joins to drop dangling references in the batch query
- Log skipped tag IDs for manual remediation
When it happens
Trigger: The 'users' containment produced an array with a null first element — typically a broken join result or users association returning placeholder nulls when the referenced user row is absent.
Common situations: Tag records referencing soft/hard-deleted users; inconsistent contain() results on large batch queries; fixtures or restored backups with dangling user foreign keys.
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
- No user found for the personal 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/2ed0c363214c62f4.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Tags/src/Service/Metadata/MigrateAllV4TagsToV5Service.php:206
/**
* @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);
$metadataClearText = json_encode($metadataArray, JSON_THROW_ON_ERROR);
$metadataEncrypted = $gpg->encrypt($metadataClearText, true);
} catch (Exception $exception) {
$msg = $exception->getMessage() . ' ';
$msg .= __('The metadata could not be encrypted with the user id: {0}.', $user->id);
throw new InternalErrorException($msg, 500, $exception);View on GitHub (pinned to 31c1bbc10f)