{"record":{"id":"2ed0c363214c62f4","repo":"passbolt/passbolt_api","slug":"user-contain-data-missing-for-the-tag-id-0","errorCode":null,"errorMessage":"User contain data missing for the tag id: \"{0}\".","messagePattern":"User contain data missing for the tag id: \"(.+?)\"\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltEe/Tags/src/Service/Metadata/MigrateAllV4TagsToV5Service.php","lineNumber":206,"sourceCode":"\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);\n            $metadataClearText = json_encode($metadataArray, JSON_THROW_ON_ERROR);\n            $metadataEncrypted = $gpg->encrypt($metadataClearText, true);\n        } catch (Exception $exception) {\n            $msg = $exception->getMessage() . ' ';\n            $msg .= __('The metadata could not be encrypted with the user id: {0}.', $user->id);\n            throw new InternalErrorException($msg, 500, $exception);","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Tags/src/Service/Metadata/MigrateAllV4TagsToV5Service.php#L188-L224","documentation":"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.","triggerScenarios":"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.","commonSituations":"Tag records referencing soft/hard-deleted users; inconsistent contain() results on large batch queries; fixtures or restored backups with dangling user foreign keys.","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."],"exampleFix":"// before\n$user = $users[0];\n// after\n$user = $users[0] ?? null;\nif ($user === null) { $this->skipped[] = $tag->id; return; }","handlingStrategy":"type-guard","validationCode":"foreach ($tags as $tag) {\n    $users = $tag->get('users');\n    if (!is_array($users) || !isset($users[0])) { $skip[] = $tag->id; }\n}","typeGuard":"function firstUser(?array $users): ?User {\n    return (isset($users[0]) && $users[0] instanceof User) ? $users[0] : null;\n}","tryCatchPattern":"try {\n    $service->migrate($uac, $batch);\n} catch (InternalErrorException $e) {\n    if (str_contains($e->getMessage(), 'User contain data missing')) {\n        $this->log('Null contained user; repair joins for tag');\n    } else { throw $e; }\n}","preventionTips":["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"],"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"}