{"record":{"id":"725297d6b12e793c","repo":"passbolt/passbolt_api","slug":"no-openpgp-key-found-for-the-user-the-metadata-could-not-be-725297","errorCode":null,"errorMessage":"No OpenPGP key found for the user. The metadata could not be encrypted with the user id: {0}.","messagePattern":"No OpenPGP key found for the user\\. The metadata could not be encrypted with the user id: (.+?)\\.","errorType":"exception","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php","lineNumber":167,"sourceCode":"     * @throws \\Cake\\Http\\Exception\\InternalErrorException When resource type mapping is does not exist.\n     */\n    private function migratePersonal(MetadataResourceDto $dto, Resource $resource): void\n    {\n        $metadataArray = $dto->getClearTextMetadata();\n\n        /** @var \\App\\Model\\Entity\\Permission $permission */\n        $permission = $resource->get('permissions')[0];\n        $user = $permission->user;\n\n        if (!isset($user)) {\n            $msg = __('No user provided.') . ' ';\n            $msg .= __('The metadata could not be encrypted for permission id: {0}.', $permission->id);\n            throw new InternalErrorException($msg);\n        }\n        if (!isset($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        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);\n        }\n\n        $this->updateResource($resource, [\n            'name' => null,\n            'username' => null,\n            'uri' => null,","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php#L149-L185","documentation":"Thrown in migratePersonal() when the permission's user exists but has no associated OpenPGP key (user->gpgkey is null). Personal-resource V5 metadata must be encrypted with that user's public key, so migration cannot proceed. The resource is skipped and the error is recorded in the migration result errors array.","triggerScenarios":"migrate() -> migratePersonal() on a resource with exactly one non-group permission whose user record exists but has no row in gpgkeys (user never completed setup, key was hard-deleted, or the Gpgkeys contain failed to match).","commonSituations":"Admin-created user accounts that never finished the OpenPGP setup flow owning personal resources; database restores that lost gpgkeys rows; users whose keys were removed during account fixes.","solutions":["Have the user complete account setup so an OpenPGP key is generated, then re-run migration.","Reassign the resource ownership to a user who has a valid OpenPGP key, then re-run migration.","Import/restore the user's missing gpgkeys row if the key exists elsewhere.","Pre-screen users with V4 personal resources for missing gpgkeys and fix accounts before running the migration."],"exampleFix":"// before: user exists but gpgkeys table has no row for user_id\n// after: reassign ownership to a user with a key\nUPDATE permissions SET aro_foreign_key = '<user-with-gpgkey-id>' WHERE id = '<permission-id>';","handlingStrategy":"validation","validationCode":"// before migrating, find active users without an OpenPGP key who own V4 resources\n$missingKeys = $usersTable->find()\n    ->leftJoinWith('Gpgkeys')\n    ->innerJoinWith('Permissions', fn ($q) => $q->where(['Permissions.aro' => 'User']))\n    ->where(['Gpgkeys.id IS' => null])\n    ->all();","typeGuard":"$gpgkey = $user->gpgkey ?? null;\nif (!$gpgkey instanceof \\App\\Model\\Entity\\Gpgkey) { skip($resource); }","tryCatchPattern":null,"preventionTips":["Require users to complete setup (key generated) before granting resource ownership.","Audit users-without-keys that own V4 resources before migration.","Back up gpgkeys table alongside users when restoring.","Reassign personal resources to keyed users when accounts are stuck in setup."],"tags":["migration","metadata","openpgp","missing-key","encryption"],"backgroundTag":"missing-dependency","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"}