passbolt/passbolt_api · error · Cake\Http\Exception\BadRequestException

The request id is invalid.

Error message

The request id is invalid.

What it means

Validation guard while fetching an account recovery request: the request id derived from the flow does not pass the uuid/validity checks after token and user assertions, so the recovery request identifier is invalid and the get fails.

Solutions

  1. Pass the account recovery request's UUID as the route id
  2. Log/inspect the request id on the client before calling the endpoint
  3. Confirm the route pattern captures the id segment correctly

Example fix

// before
GET /account-recovery/requests/123
// after
GET /account-recovery/requests/6d3c4d99-7c1f-4d3e-8b76-0a3f9d2c1a55
Defensive patterns

Strategy: validation

Validate before calling

if (!Validation::uuid($requestId)) { // do not call the endpoint; fix the id source first }

Type guard

function isUuid(?string $v): bool { return is_string($v) && (bool)preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $v); }

Try / catch

try { $service->get($requestId, $userId, $token); } catch (BadRequestException $e) { if (str_contains($e->getMessage(), 'request id is invalid')) { fixRouteOrIdSource(); } }

Prevention

When it happens

Trigger: Calling getNotCompletedOrFail()/get() (GET /account-recovery/requests/{id}) with an id that fails Validation::uuid(): missing, empty, numeric, or malformed string.

Common situations: Route parameter not populated (wrong route template); client concatenates URL incorrectly; passing an internal numeric id instead of the request UUID.

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/edccb9d1c9ade256. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryRequests/AccountRecoveryRequestGetService.php:157

        string $token,
        ?string $clientIp = null
    ): AccountRecoveryRequest {
        // Assert policy is not set to disabled
        (new AccountRecoveryOrganizationPolicyGetService())->getOrFail();

        // Assert token exist and is valid and belong to the user and is of the right type
        $tokenService = new AuthenticationTokenGetService();
        $tokenEntity = $tokenService->getActiveOrFail($token, $userId, AuthenticationToken::TYPE_RECOVER);

        // Assert user exist, is active and not deleted
        $userEntity = (new UserGetService())->getActiveNotDeletedNotDisabledOrFail($userId);

        // Assert user is enrolled in the program
        (new AccountRecoveryUserSettingsGetService())->getOrFail($userId);

        // Assert request entity exist and belong to the user
        if (!Validation::uuid($requestId)) {
            throw new BadRequestException(__('The request id is invalid.'));
        }
        try {
            $where = [
                'id' => $requestId,
                'user_id' => $userEntity->id,
                'authentication_token_id' => $tokenEntity->id,
            ];
            /** @var \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryRequest $requestEntity */
            $requestEntity = $this->AccountRecoveryRequests->find()->where($where)->firstOrFail();
        } catch (RecordNotFoundException $exception) {
            $this->onRequestDoesNotExist($requestId, $userId, $clientIp ?? '0.0.0.0');
            throw new NotFoundException(__('The account recovery request could not be found.'));
        }

        // Assert request is not already completed
        if ($requestEntity->isCompleted()) {
            throw new BadRequestException(__('The request is already completed.'));
        }

View on GitHub (pinned to 31c1bbc10f)