flarum/framework · warning · ValidationException
This erasure request has already been processed.
Error message
This erasure request has already been processed.
What it means
ConfirmErasureController rejects confirmation if the erasure request status is already STATUS_PROCESSED or STATUS_MANUAL, throwing this ValidationException — the request has reached a terminal state and cannot be confirmed again.
Solutions
- Do nothing further — the erasure request is already completed; no action is needed.
- If a new erasure is required, submit a fresh erasure request.
- Check erasure_requests.status in the database to confirm the terminal state before retrying.
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
if (in_array($erasureRequest->status, [ErasureRequest::STATUS_PROCESSED, ErasureRequest::STATUS_MANUAL])) { /* skip confirmation; show 'already processed' */ } Try / catch
try { $http->get($confirmUrl); } catch (ValidationException $e) { if (isset($e->getErrors()['request'])) { /* treat as no-op / show status */ } } Prevention
- Make confirmation idempotent in your client (track processed state)
- Purge old confirmation emails after processing
- Check status via API before re-confirming
When it happens
Trigger: Clicking the erasure confirmation link (or re-submitting it) after the request was already fully processed (STATUS_PROCESSED) or handled manually (STATUS_MANUAL).
Common situations: Double-clicking the emailed link; re-visiting an old confirmation email after the request was completed; an admin already processed the request in the backend.
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.
Related errors
- Invalid erasure mode: $mode
- Erase requests cannot be confirmed by different users.
- Failed to open file at $filePath
AI-assisted analysis of flarum/framework@4b939f6853 (2026-09-15).
Data as JSON: /api/errors/a713362a3bcedabc.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/gdpr/src/Http/Controller/ConfirmErasureController.php:51
{
$actor = RequestUtil::getActor($request);
$token = Arr::get($request->getQueryParams(), 'token');
/** @var ErasureRequest $erasureRequest */
$erasureRequest = ErasureRequest::query()
->with('user')
->where('verification_token', $token)
->firstOrFail();
/**
* @TODO: the token is enough to confirm the erasure request. We should not require the user to be logged in.
*/
if ($erasureRequest->user->isNot($actor) && ! $actor->isGuest()) {
throw new ValidationException(['user' => 'Erase requests cannot be confirmed by different users.']);
}
if (in_array($erasureRequest->status, [ErasureRequest::STATUS_PROCESSED, ErasureRequest::STATUS_MANUAL])) {
throw new ValidationException(['request' => 'This erasure request has already been processed.']);
}
$ip = $request->getAttribute('ipAddress');
$erasureRequest->user_confirmed_at = Carbon::now();
$erasureRequest->status = ErasureRequest::STATUS_USER_CONFIRMED;
$erasureRequest->cancelled_at = null;
$erasureRequest->verification_token = null;
$erasureRequest->confirmation_ip = $ip;
$erasureRequest->save();
// Attribute to the request's owner: confirmation may arrive via the
// emailed token while logged out, so $actor can be a guest.
$this->events->dispatch(new ErasureConfirmed($erasureRequest->user, $erasureRequest));
return new RedirectResponse($this->url->to('forum')->base().'?erasureRequestConfirmed=1');
}
}View on GitHub (pinned to 4b939f6853)