passbolt/passbolt_api · error · CustomValidationException
The authentication token is not valid.
Error message
The authentication token is not valid.
What it means
consumeActiveNotExpiredOrFail atomically deactivates the token via setInactive(). If the update affects no rows, another request already consumed the token in a race, so this method throws CustomValidationException('The authentication token is not valid.') with a 'token.isActive' error mirroring getActiveOrFail's contract.
Solutions
- Treat the exception as a consumed-token case and show the user an 'already used link' message.
- Reload the setup/complete page to get a fresh token state and an accurate error.
- Idempotent-guard clients: disable the submit action after the first request.
- If the user is actually stuck, issue a new authentication token (e.g. resend setup email).
Defensive patterns
Strategy: try-catch
Try / catch
try {
$token = $service->consumeActiveNotExpiredOrFail($token, $userId, $type);
} catch (CustomValidationException $e) {
$errors = $e->getErrors();
if (isset($errors['token']['isActive'])) {
// token already consumed — show 'link already used' page
}
} Prevention
- Disable submit buttons after first request to avoid double consumption
- Detect the token.isActive error key to give accurate UX
- Educate users that links are single-use
When it happens
Trigger: Two requests consume the same valid, unexpired register/complete-setup token concurrently and both pass getActiveNotExpiredOrFail; the loser's setInactive() returns false.
Common situations: User double-clicks a setup link or the setup page auto-submits while the user clicks manually; duplicated email-link deliveries; retries after slow responses.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The authentication token could not be found.
- The authentication token is not valid.
- " " is not a valid search filter.
- " " is not a valid search filter. It is not a UTF8 string.
- " " is not a valid search filter. It should be between 1…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/6589df0ec34f0e7b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/AuthenticationTokens/AuthenticationTokenConsumeService.php:57
* @throws \Cake\Http\Exception\NotFoundException if token is not found
* @throws \App\Error\Exception\CustomValidationException if the token is expired, inactive, or lost a concurrent-consume race
* @throws \Cake\Http\Exception\BadRequestException if token id is not a valid uuid
*/
public function consumeActiveNotExpiredOrFail(
string $token,
string $userId,
string $type,
?string $expiry = null
): AuthenticationToken {
$authenticationToken = (new AuthenticationTokenGetService())
->getActiveNotExpiredOrFail($token, $userId, $type, $expiry);
/** @var \App\Model\Table\AuthenticationTokensTable $authTokensTable */
$authTokensTable = $this->fetchTable('AuthenticationTokens');
if (!$authTokensTable->setInactive($authenticationToken->token)) {
// Lost the concurrent-consume race — mirror `getActiveOrFail`'s "already consumed" contract.
$error = ['token' => ['isActive' => __('The token is already consumed.')]];
throw new CustomValidationException(__('The authentication token is not valid.'), $error);
}
$authenticationToken->set('active', false);
$authenticationToken->setDirty('active', false);
return $authenticationToken;
}
}
View on GitHub (pinned to 31c1bbc10f)