{"record":{"id":"7a6386f16a8a089f","repo":"passbolt/passbolt_api","slug":"the-account-recovery-request-status-is-not-approved","errorCode":null,"errorMessage":"The account recovery request status is not approved.","messagePattern":"The account recovery request status is not approved\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoveryRecoverCompleteService.php","lineNumber":86,"sourceCode":"                    'AuthenticationTokens.token' => $this->request->getData('authenticationtoken.token'),\n                ]);\n            })\n            ->where([\n                'AccountRecoveryRequests.id' => $requestId,\n                'AccountRecoveryRequests.user_id' => $token->user_id,\n            ])\n            ->contain('AccountRecoveryResponses', function (Query $query) {\n                return $query\n                    ->select([\n                        'AccountRecoveryResponses.id',\n                        'AccountRecoveryResponses.account_recovery_request_id',\n                        'AccountRecoveryResponses.data',\n                    ]);\n            })\n            ->firstOrFail();\n\n        if (!$request->isApproved()) {\n            throw new BadRequestException(__('The account recovery request status is not approved.'));\n        }\n\n        $this->AuthenticationTokens->hasOne('Passbolt/AccountRecovery.AccountRecoveryRequests');\n        $request->setAccess([\n            'status',\n            'modified_by',\n            'account_recovery_responses',\n        ], true);\n        $request->status = AccountRecoveryRequest::ACCOUNT_RECOVERY_REQUEST_COMPLETED;\n        $request->modified_by = $token->user_id;\n\n        foreach ($request->account_recovery_responses as $response) {\n            $response->setAccess(['data', 'modified_by'], true);\n            $response->data = null;\n            $response->modified_by = $token->user_id;\n        }\n        $request->setDirty('account_recovery_responses');\n        $token->set('account_recovery_request', $request);","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoveryRecoverCompleteService.php#L68-L104","documentation":"Thrown during account recovery setup/recover completion when the pending account recovery request associated with the authentication token exists but its status is not 'approved'. Passbolt only allows completing a recovery workflow once an administrator has approved the request, so any other status (pending, rejected, etc.) is rejected as a bad request.","triggerScenarios":"Calling the setup/recover complete endpoint (POST /setup/recover/complete/<userId>/<tokenId> or setup complete) where the AccountRecoveryRequests row linked to the user still has status other than 'approved' — e.g. the admin never approved the request, or the request was created/recreated after approval, or a stale token references a superseded request.","commonSituations":"Admin approval workflow not finished before the user completes setup; user re-initiates account recovery (creating a new pending request) but the browser still holds an old approved token flow; environment restored from backup with reset request statuses; testing the recover flow without running the organization recovery settings approval step.","solutions":["Have an administrator review and approve the account recovery request (Admin Workspace > Account Recovery) so its status becomes 'approved', then retry the complete call","Restart the recovery flow from the beginning to generate a fresh request, and ensure it is approved before completing","Verify the organization account recovery policy is enabled and the request corresponds to the current user/token pair (stale tokens reference old requests)","Check the account_recovery_requests table status for the user to confirm the workflow state before debugging client code"],"exampleFix":"// before: completing with a pending request\nawait passbolt.setupRecoverComplete(userId, tokenId);\n// after: ensure the request is approved first (admin action), then retry;\n// client can pre-check via GET /account-recovery/requests for status === 'approved'","handlingStrategy":"try-catch","validationCode":"const req = await fetch(`/account-recovery/requests?user_id=${userId}`);\nconst status = (await req.json())?.status;\nif (status !== 'approved') throw new Error('Request not approved yet');","typeGuard":"const isApproved = (r) => r && typeof r.status === 'string' && r.status === 'approved';","tryCatchPattern":"try {\n  await passbolt.accountRecovery.complete(userId, tokenId);\n} catch (e) {\n  if (e.code === 400 && /not approved/.test(e.message)) {\n    notifyAdminForApproval();\n  } else { throw e; }\n}","preventionTips":["Always complete the admin approval step before calling the complete endpoint","Surface request status in the UI and block the complete call until 'approved'","Restart the recovery flow instead of reusing old tokens","Watch the account_recovery_requests table status during integration testing"],"tags":["account-recovery","workflow-state","http-400"],"backgroundTag":"invalid-state-transition","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"}