{"record":{"id":"dd4d048844d40e95","repo":"passbolt/passbolt_api","slug":"exceptionmessage-the-metadata-could-not-be-encrypted-with-dd4d04","errorCode":null,"errorMessage":"{exceptionMessage} The metadata could not be encrypted with the user id: {0}.","messagePattern":"(.+?) 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":179,"sourceCode":"            $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,\n            'description' => null,\n            'resource_type_id' => $this->getV5ResourceType($resource->resource_type_id),\n            'metadata' => $metadataEncrypted,\n            'metadata_key_id' => $user->gpgkey->id,\n            'metadata_key_type' => 'user_key',\n        ]);\n    }\n\n    /**\n     * @param \\Passbolt\\Metadata\\Model\\Dto\\MetadataResourceDto $dto DTO.\n     * @param \\App\\Model\\Entity\\Resource $resource Resource entity.\n     * @return void","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php#L161-L197","documentation":"During migration of v4 resources to v5 metadata, the personal-resource path encrypts the resource's metadata with the owner's OpenPGP key. If $gpg->encrypt() throws (missing/invalid user key, keyring failure, bad clear text), the exception is wrapped in a CakePHP InternalErrorException with this appended message identifying the user whose key failed.","triggerScenarios":"migrate() -> migratePersonal() calls setEncryptKeyWithUserKey($gpg, $user->gpgkey) and then encrypt(); the user has no GPG key, the key is not in the server keyring, the key is expired/revoked, or json_encode of $metadataArray throws.","commonSituations":"Migration command (migrateMetadata resources) run on a server where some users' public keys were never imported; user deleted their account key or key was rotated without re-import; GnuPG extension keyring permission issues on the host.","solutions":["Verify the user has an enabled GPG key (users.gpgkey) and that the public key exists in the server keyring (gpg --list-keys <fingerprint>), import it if missing","Re-run the migration with debug enabled to see the underlying wrapped exception message (it is prefixed before this text)","Check PHP GnuPG/pear-crypt-gpg configuration and keyring home directory permissions for the web server user","Fix or reset the affected user's key data, then re-run the migration for the failing resource"],"exampleFix":"// before: user without key discovered mid-migration\n$metadataEncrypted = $gpg->encrypt($metadataClearText, true); // throws\n// after: pre-check before migrating\nif (!$user->gpgkey || $user->gpgkey->deleted) {\n    throw new RecordNotFoundException(__('User {0} has no usable GPG key.', $user->id));\n}\n$metadataEncrypted = $gpg->encrypt($metadataClearText, true);","handlingStrategy":"try-catch","validationCode":"// before migration, per user\nif (!$user->gpgkey || $user->gpgkey->deleted) {\n    throw new \\LogicException(\"User {$user->id} has no GPG key\");\n}\n$fp = $user->gpgkey->fingerprint;\n$inKeyring = in_array($fp, OpenPGPBackend::getFingerprintsInKeyring(), true);\nif (!$inKeyring) {\n    throw new \\LogicException(\"Key {$fp} not in server keyring\");\n}","typeGuard":"function hasUsableGpgKey(\\App\\Model\\Entity\\User $user): bool {\n    return $user->gpgkey !== null\n        && $user->gpgkey->deleted === false\n        && is_string($user->gpgkey->fingerprint)\n        && strlen($user->gpgkey->fingerprint) === 40;\n}","tryCatchPattern":"try {\n    $metadataEncrypted = $gpg->encrypt($metadataClearText, true);\n} catch (\\Exception $e) {\n    // inspect $e->getMessage(); if keyring missing, import user key then retry once\n}","preventionTips":["Ensure the import command syncs all users' public keys into the server keyring before migrating","Health-check user GPG keys (deleted/expired) before running bulk migrations","Keep PHP gnupg/crypt-gpg extensions and keyring directory permissions verified on the host"],"tags":["openpgp","encryption","migration","metadata","gpg-key"],"backgroundTag":"http-error-response","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"}