{"record":{"id":"0ba5880605e3b412","repo":"passbolt/passbolt_api","slug":"could-not-save-the-account-recovery-private-key","errorCode":null,"errorMessage":"Could not save the account recovery private key.","messagePattern":"Could not save the account recovery private key\\.","errorType":"validation","errorClass":"ValidationException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoverySetupCompleteService.php","lineNumber":188,"sourceCode":"     * @param \\App\\Model\\Entity\\User $user User entity\n     * @param array|null $saveOptions options\n     * @return \\App\\Model\\Entity\\User\n     */\n    protected function saveUserEntity(User $user, ?array $saveOptions = []): User\n    {\n        $user = parent::saveUserEntity($user, $saveOptions);\n\n        if ($this->isAccountRecoveryUserSettingProvided()) {\n            if ($user->get('account_recovery_user_setting')->hasErrors()) {\n                throw new ValidationException(\n                    'Could not save the account recovery setting.',\n                    $user->get('account_recovery_user_setting'),\n                    $this->AccountRecoveryUserSettings\n                );\n            }\n\n            if ($user->hasValue('account_recovery_private_key') && $user->get('account_recovery_private_key')->hasErrors()) { // phpcs:ignore\n                throw new ValidationException(\n                    'Could not save the account recovery private key.',\n                    $user->get('account_recovery_private_key'),\n                    $this->AccountRecoveryPrivateKeys\n                );\n            }\n        }\n\n        return $user;\n    }\n}\n","sourceCodeStart":170,"sourceCodeEnd":199,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoverySetupCompleteService.php#L170-L199","documentation":"Thrown when the account_recovery_private_key association attached to the user entity fails validation while saving during account recovery setup completion. The private key to be escrowed is malformed (e.g. not a valid OpenPGP key message) or violates entity rules, and the ValidationException exposes the errors plus the AccountRecoveryPrivateKeys table.","triggerScenarios":"POST setup complete where the provided account recovery private key entity has validation errors — invalid armored key, missing required fields (data, user_id), or key not decryptable/associated correctly.","commonSituations":"Client encrypts the recovery key with the wrong organization key; corrupted or truncated armored key in the payload; custom integrations posting raw keys instead of the expected structure; key generated by an unsupported OpenPGP implementation.","solutions":["Check the errors object in the ValidationException response to identify the failing key field","Verify the private key is armored, complete, and encrypted for the organization recovery key before sending","Ensure the key is generated/encrypted with a supported OpenPGP implementation (GnuPG/OpenPGP.js as used by the extension)","Regenerate the recovery data by restarting the setup flow with a current browser extension version"],"exampleFix":"// before\nkeyPayload = { data: rawPrivateKeyString }; // unencrypted/invalid\n// after\nkeyPayload = { data: await encryptForOrgRecoveryKey(privateKeyArmored) };","handlingStrategy":"try-catch","validationCode":"if (!/-----BEGIN PGP MESSAGE-----/.test(payload.account_recovery_private_key?.data ?? '')) {\n  throw new Error('Recovery private key must be an armored encrypted message');\n}","typeGuard":"const isValidRecoveryKey = (k) => k != null && typeof k.data === 'string' && k.data.startsWith('-----BEGIN PGP MESSAGE-----');","tryCatchPattern":"try {\n  await setupComplete(payload);\n} catch (e) {\n  if (e.name === 'ValidationException' && e.errors?.account_recovery_private_key) {\n    restartKeyEncryptionStep();\n  } else { throw e; }\n}","preventionTips":["Always encrypt the recovery private key with the organization recovery public key","Use the OpenPGP library shipped with the extension rather than custom crypto","Check the errors object in the 400 response for the exact field problem","Restart the setup flow to regenerate recovery data after encryption failures"],"tags":["account-recovery","openpgp","validation","entity-save"],"backgroundTag":"schema-validation-failed","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"}