flarum/framework · error · ValidationException

Erase requests cannot be confirmed by different users.

Error message

Erase requests cannot be confirmed by different users.

What it means

ConfirmErasureController handles the erasure confirmation link and requires that the actor either is the owner of the erasure request or is a guest; a logged-in user confirming another user's request throws this ValidationException. The token alone identifies the request, so identity mismatch is rejected.

Solutions

  1. Log out (or use an incognito window) so you are a guest, then open the confirmation link.
  2. Open the link in a browser profile where the request owner is logged in.
  3. Confirm the link/token belongs to the currently logged-in user; request a new erasure confirmation email if unsure.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

// before opening the confirmation link, ensure session state:
// guest OR logged in as the request owner
if ($actor->isGuest() === false && $erasureRequest->user_id !== $actor->id) { /* do not request */ }

Try / catch

try { $http->get($confirmUrl); } catch (ValidationException $e) { if (isset($e->getErrors()['user'])) { /* advise logout or correct account */ } }

Prevention

When it happens

Trigger: Visiting the erasure confirmation URL while logged in as a user different from the request's owner (erasureRequest->user->isNot(actor) and actor not guest).

Common situations: Admin or another account is logged in when the user clicks the emailed confirmation link; shared computer with another session; testing the confirmation link in the wrong browser profile.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of flarum/framework@4b939f6853 (2026-09-15). Data as JSON: /api/errors/fb6ffc5e3cbaab7c. Report an issue: GitHub.

Appendix: source

Thrown at extensions/gdpr/src/Http/Controller/ConfirmErasureController.php:47

    {
    }

    public function handle(Request $request): ResponseInterface
    {
        $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));

View on GitHub (pinned to 4b939f6853)