user() * comes back null. Four components each dereferenced it unguarded * ($operator->password, ->id, ->two_factor_recovery_codes, …), turning that * into a 500 instead of a sign-in prompt. * * currentOperator() cannot throw its way out of the null case. Livewire only * turns $this->redirect() into a browser navigation once the calling action * returns NORMALLY: the redirect is queued as component state and picked up * during Livewire's own dehydrate step (Livewire\Features\SupportRedirects), * which runs strictly after the called method returns — an uncaught * exception during the call skips it entirely and Livewire ships back a bare * error response instead (confirmed by reading * Livewire\Mechanisms\HandleComponents::update() and * Livewire\Mechanisms\HandleRequests::handleUpdate(), which catches nothing * but \TypeError). So this returns null and every caller checks for it: * * if (! $operator = $this->currentOperator()) { * return; * } * * That one-line guard is the only thing left for a caller to get wrong; the * redirect target and the mechanism live here once, so the four cannot drift * apart the way the original unguarded dereferences did. */ trait ResolvesOperator { protected function currentOperator(): ?Operator { $operator = Auth::guard('operator')->user(); if ($operator === null) { $this->redirect(route('admin.login')); } return $operator; } }