monicahq/monica · error · ModelNotFoundException

The password is not valid.

Error message

The password is not valid.

What it means

Cancelling a Monica account requires re-entering the current password. CancelAccountController::destroy() runs Hash::check(input, Auth::user()->password); on mismatch it throws ModelNotFoundException — an unconventional exception choice that surfaces as HTTP 404. On success it dispatches the queued CancelAccount job which destroys the account asynchronously.

Source

Thrown at app/Domains/Settings/CancelAccount/Web/Controllers/CancelAccountController.php:28

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Inertia\Inertia;

class CancelAccountController extends Controller
{
    public function index()
    {
        return Inertia::render('Settings/CancelAccount/Index', [
            'layoutData' => VaultIndexViewHelper::layoutData(),
            'data' => CancelAccountViewHelper::data(),
        ]);
    }

    public function destroy(Request $request)
    {
        if (! Hash::check($request->input('password'), Auth::user()->password)) {
            throw new ModelNotFoundException('The password is not valid.');
        }

        $data = [
            'account_id' => Auth::user()->account_id,
            'author_id' => Auth::id(),
        ];

        CancelAccount::dispatch($data);

        return response()->json([
            'data' => route('login'),
        ], 200);
    }
}

View on GitHub (pinned to e08e917341)

Solutions

  1. Re-enter the account's current password and resubmit
  2. If forgotten, complete the password reset flow first, then cancel
  3. In tests/API scripts, create the user with a known bcrypt password (Hash::make('secret')) so the check passes
  4. Treat any non-200 (here 404) as 'not cancelled' — the destructive job only runs after a 200 response
Defensive patterns

Strategy: try-catch

Validate before calling

// Client-side pre-check: never submit an empty password to the destructive endpoint
if (typeof password !== 'string' || password.length === 0) {
    showError('Enter your current password to cancel the account.');
    return;
}

Try / catch

// HTTP client consuming the endpoint: a 404 means wrong password, account NOT deleted
const response = await fetch('/cancellations', { method: 'POST', body: formData });
if (response.status === 404) {
    showError('The password is not valid. Your account was not deleted.');
    return; // allow retry
}
if (!response.ok) throw new Error('Unexpected error');
// only a 200 means CancelAccount was dispatched

Prevention

When it happens

Trigger: POSTing the cancel-account form (or equivalent API request) with a password that does not match the stored bcrypt hash: typo, stale autofill, or the password changed in another session after the form was loaded.

Common situations: Caps-lock/typos, password rotated elsewhere, password managers with an outdated entry, or accounts that never stored a local password (Hash::check against a null hash always fails).

Related errors


AI-assisted analysis of monicahq/monica@e08e917341 (2026-08-17). Data as JSON: /api/errors/e28710095c130d90. Report an issue: GitHub.