passbolt/passbolt_api · error · ValidationException
Could not update the authentication token data.
Error message
Could not update the authentication token data.
What it means
Thrown by RecoverCompleteService::complete when saving the freshly built authentication token entity back to the authentication_tokens table fails entity validation. The token was already consumed in memory, so a failed save leaves the recovery in an inconsistent state and surfaces as a ValidationException.
Solutions
- Run pending migrations (ddev refresh / cake migrations migrate) so authentication_tokens matches the expected schema
- Retry the recover-complete request once the database is healthy; if it persists, inspect the entity errors via the ValidationException detail
- Check the authentication_tokens row for the token id and fix or remove the corrupted row
- Verify database connectivity and that no migration lock is held
Defensive patterns
Strategy: retry
Validate before calling
// ensure migrations are current before the flow await ensureMigrationsUpToDate(); // cake migrations status / migrate
Try / catch
try { await recoverComplete(userId, token, key); }
catch (e) { if (isTokenSaveValidation(e)) { await retryWithBackoff(() => recoverComplete(...), 1); } else throw e; } Prevention
- Keep database migrations applied (ddev refresh)
- Monitor DB health/locks during recovery flows
- Inspect ValidationException entity errors when it recurs
- Restore consistent state in authentication_tokens after corruption
When it happens
Trigger: Database-level validation failure on the token entity during update — e.g. schema constraint mismatch, unexpected field state, or a database connectivity/lock issue surfacing as a save error.
Common situations: Database schema drift after an incomplete migration; MariaDB/Postgres-specific column incompatibility; concurrent writes locking the row; corrupted token row in authentication_tokens.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The authentication token does not exist or has been deleted.
- Ajax/Json request not supported.
- SsoRecover plugin is disabled.
- The authentication token does not exist or has been deleted.
- The authentication token has been expired.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/d33d483b336fcb2b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/Setup/RecoverCompleteService.php:54
* @throws \Cake\Http\Exception\BadRequestException if no authentication token was provided
* @throws \Cake\Http\Exception\BadRequestException if the authentication token is not a uuid
* @throws \Cake\Http\Exception\BadRequestException if the authentication token is expired or invalid
* @throws \Cake\Http\Exception\BadRequestException if the OpenPGP key is not provided or not a valid OpenPGP key
* @throws \Cake\Http\Exception\BadRequestException if the OpenPGP key does not belong to the user
* @throws \App\Error\Exception\CustomValidationException if the token was already consumed by a concurrent request
* @param string $userId uuid of the user
* @return void
*/
public function complete(string $userId): void
{
$this->AuthenticationTokens->getConnection()->transactional(function () use ($userId): void {
$user = $this->validateData($userId);
$token = $this->buildAuthenticationTokenEntity($userId);
$this->consumeTokenOrFail($token);
if (!$this->AuthenticationTokens->save($token)) {
throw new ValidationException(
__('Could not update the authentication token data.'),
$token,
$this->AuthenticationTokens
);
}
$this->dispatchEvent(RecoverCompleteServiceInterface::COMPLETE_SUCCESS_EVENT_NAME, [
'user' => $user,
'data' => $this->request->getData(),
'clientIp' => $this->request->clientIp(),
'userAgent' => $this->request->getEnv('HTTP_USER_AGENT'),
]);
});
}
/**
* Extension seam: subclasses may attach associations that `complete()` will cascade-save.
*View on GitHub (pinned to 31c1bbc10f)