{"record":{"id":"a6a2f1a5ca5f47b7","repo":"passbolt/passbolt_api","slug":"no-user-found-for-the-personal-tag-id-0","errorCode":null,"errorMessage":"No user found for the personal tag id: \"{0}\".","messagePattern":"No user found for the personal tag id: \"(.+?)\"\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltEe/Tags/src/Service/Metadata/MigrateAllV4TagsToV5Service.php","lineNumber":200,"sourceCode":"            'metadata' => $metadataEncrypted,\n            'metadata_key_id' => $metadataKey->id,\n            'metadata_key_type' => MetadataKey::TYPE_SHARED_KEY,\n            'is_shared' => true,\n        ]);\n    }\n\n    /**\n     * @param \\Passbolt\\Tags\\Model\\Dto\\MetadataTagDto $dto DTO.\n     * @param \\Passbolt\\Tags\\Model\\Entity\\Tag $tag Tag entity.\n     * @return void\n     */\n    private function migratePersonal(MetadataTagDto $dto, Tag $tag): void\n    {\n        $metadataArray = $dto->getClearTextMetadata();\n        $users = $tag->get('users');\n\n        if (!is_array($users) || count($users) < 1) {\n            throw new InternalErrorException(__('No user found for the personal tag id: \"{0}\".', $tag->id));\n        }\n\n        /** @var \\App\\Model\\Entity\\User $user */\n        $user = $users[0];\n        if (is_null($user)) {\n            throw new InternalErrorException(__('User contain data missing for the tag id: \"{0}\".', $tag->id));\n        }\n        if (is_null($user->gpgkey)) {\n            $msg = __('No OpenPGP key found for the user.') . ' ';\n            $msg .= __('The metadata could not be encrypted with the user id: {0}.', $user->id);\n            throw new InternalErrorException($msg);\n        }\n\n        try {\n            $gpg = OpenPGPBackendFactory::get();\n            $gpg->clearKeys();\n            $gpg = $this->setSignKeyWithServerKey($gpg);\n            $gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey);","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Tags/src/Service/Metadata/MigrateAllV4TagsToV5Service.php#L182-L218","documentation":"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.","triggerScenarios":"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.","commonSituations":"Orphaned tags left by deleted users without cleanup; migration batch query missing ->contain('Users'); partially deleted resource-tag relations from older versions.","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."],"exampleFix":"// before\n$tags = $this->Tags->find()->all();\n// after\n$tags = $this->Tags->find()->contain(['Users'])->where(['Tags.is_shared' => false])->all();","handlingStrategy":"validation","validationCode":"$orphanTags = $tagsTable->find()\n    ->contain(['Users'])\n    ->where(['is_shared' => false])\n    ->all()\n    ->filter(fn($t) => count($t->get('users') ?? []) === 0);","typeGuard":"function hasOwner(?Tag $tag): bool {\n    $users = $tag?->get('users');\n    return is_array($users) && count($users) > 0 && $users[0] !== null;\n}","tryCatchPattern":"try {\n    $service->migrate($uac, $batch);\n} catch (InternalErrorException $e) {\n    if (str_contains($e->getMessage(), 'No user found for the personal tag')) {\n        $this->log('Orphaned tag; exclude from batch and clean up');\n    } else { throw $e; }\n}","preventionTips":["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"],"tags":["migration","data-integrity","tags"],"backgroundTag":"record-not-found","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"}