passbolt/passbolt_api · error · BadRequestException

The account recovery request identifier should be a valid…

Error message

The account recovery request identifier should be a valid UUID.

What it means

validateAccountRecoveryRequestId() validates the account recovery request id before building the authentication token: the organization policy must exist and the requestId must be a UUID, otherwise BadRequestException. Also loads the request row from AccountRecoveryRequests afterwards.

Solutions

  1. Send the exact account recovery request UUID returned when the recovery request was started
  2. Validate the id with a UUID check client-side before calling
  3. Ensure you are passing the request id, not a token or user id
  4. Update the client if it builds the completion URL incorrectly

Example fix

// before
const requestId = response.token; // wrong id
// after
const requestId = response.account_recovery_request_id;
if (!isUuid(requestId)) throw new Error('invalid request id');
Defensive patterns

Strategy: validation

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; if (!UUID_RE.test(requestId)) throw new Error('request id must be a UUID');

Type guard

const isUuid = (v) => typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);

Try / catch

try { await completeRecovery(requestId); } catch (e) { if (e.status === 400 && /valid UUID/.test(e.message)) { /* re-fetch request id from the start flow */ } }

Prevention

When it happens

Trigger: Calling the account recovery setup/recover complete endpoint with a malformed or empty requestId (not a UUID); client sending a request id from a different source or truncated identifier.

Common situations: Clients storing the request id as an integer or string with whitespace; copying an id from a different flow (e.g. authentication token id instead of request id); old client versions with wrong URL construction.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/28a94adf9bcf83e9. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoveryRecoverCompleteService.php:59

        return $token;
    }

    /**
     * @param \App\Model\Entity\AuthenticationToken $token Token being updated
     * @param string $requestId The request ID
     * @return \App\Model\Entity\AuthenticationToken
     * @throws \Cake\Datasource\Exception\RecordNotFoundException if the request was not found
     * @throws \Cake\Http\Exception\BadRequestException if the request is not in "approved" status
     */
    protected function validateAccountRecoveryRequestId(
        AuthenticationToken $token,
        string $requestId
    ): AuthenticationToken {
        (new AccountRecoveryOrganizationPolicyGetService())->getOrFail();

        if (!Validation::uuid($requestId)) {
            throw new BadRequestException(__('The account recovery request identifier should be a valid UUID.'));
        }

        $RequestsTable = TableRegistry::getTableLocator()->get('Passbolt/AccountRecovery.AccountRecoveryRequests');

        /** @var \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryRequest $request */
        $request = $RequestsTable->find()
            ->innerJoinWith('AuthenticationTokens', function (Query $q) {
                return $q->where([
                    'AuthenticationTokens.token' => $this->request->getData('authenticationtoken.token'),
                ]);
            })
            ->where([
                'AccountRecoveryRequests.id' => $requestId,
                'AccountRecoveryRequests.user_id' => $token->user_id,
            ])
            ->contain('AccountRecoveryResponses', function (Query $query) {
                return $query
                    ->select([

View on GitHub (pinned to 31c1bbc10f)