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
- Regenerate the link ensuring the full user UUID is in the URL
- Validate the user id with Cake\Validation::uuid() before calling
- Check the email template/route builder that composes the URL
- 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
- Compose status URLs from entity UUID fields only
- Validate all three identifiers (requestId, userId, tokenId) before calling
- Verify email templates render every URL segment
- Log full URLs when debugging malformed recovery links
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
- The authentication token id is invalid.
- The request data is invalid: id invalid.
- The user id is invalid.
- " " is not a valid search filter.
- " " is not a valid search filter. It is not a UTF8 string.
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)