passbolt/passbolt_api · error · BadRequestException

The user id is invalid.

Error message

The user id is invalid.

What it means

BadRequestException thrown by AccountRecoveryRequestsGetController::get() when the userId route parameter is missing or not a valid UUID. The controller validates requestId, userId and tokenId formats before fetching the recovery request.

Solutions

  1. Regenerate the link ensuring the full user UUID is in the URL
  2. Validate the user id with Cake\Validation::uuid() before calling
  3. Check the email template/route builder that composes the URL
  4. Log the request URL to confirm which segment is malformed

Example fix

// before
$url = "/account-recovery/requests/{$requestId}/{$username}/{$tokenId}.json";
// after
$url = "/account-recovery/requests/{$requestId}/{$user->id}/{$tokenId}.json";
Defensive patterns

Strategy: validation

Validate before calling

if (!isValidUuid(userId)) throw new Error('user id must be a UUID');
if (!isValidUuid(requestId)) throw new Error('request id must be a UUID');
if (!isValidUuid(tokenId)) throw new Error('token id must be a UUID');

Type guard

function isValidUuid(value: unknown): value is string {
  return typeof value === 'string'
    && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
}

Try / catch

try {
  await accountRecoveryRequestService.get(requestId, userId, tokenId);
} catch (ApiError e) {
  if (e.message.includes('user id is invalid')) {
    redirectToRecoveryStart(); // regenerate a valid link
  }
}

Prevention

When it happens

Trigger: GET /account-recovery/requests/<requestId>/<bad-user-id>/<tokenId>.json with the user id missing, empty, or not a UUID.

Common situations: Recovery status-link generated with a placeholder or truncated user id; client passing a username instead of UUID; template variable left unrendered in the email link.

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

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Controller/AccountRecoveryRequests/AccountRecoveryRequestsGetController.php:56

        $this->Authentication->allowUnauthenticated(['get']);

        parent::beforeFilter($event);
    }

    /**
     * Gets an account recovery request
     * Sends an email to the admins on suspect request
     *
     * @param string|null $requestId Request ID
     * @param string|null $userId User ID
     * @param string|null $tokenId Token ID
     * @return void
     * @throws \Cake\Http\Exception\BadRequestException if the data provided is not valid
     */
    public function get(?string $requestId, ?string $userId, ?string $tokenId): void
    {
        if (!isset($userId) || !Validation::uuid($userId)) {
            throw new BadRequestException(__('The user id is invalid.'));
        }
        if (!isset($tokenId) || !Validation::uuid($tokenId)) {
            throw new BadRequestException(__('The authentication token id is invalid.'));
        }
        if (!isset($requestId) || !Validation::uuid($requestId)) {
            throw new BadRequestException(__('The request id is invalid.'));
        }

        $ip = $this->getRequest()->clientIp();

        $service = new AccountRecoveryRequestGetService();
        $requestEntity = $service->getNotCompletedOrFail($requestId, $userId, $tokenId, $ip);
        $data = $service->decorateResults($requestEntity);

        $this->success(__('The operation was successful.'), $data);
    }
}

View on GitHub (pinned to 31c1bbc10f)