BookStackApp/BookStack · error · LoginAttemptInvalidUserException

Login not allowed for guest user

Error message

Login not allowed for guest user

What it means

LoginService::login explicitly rejects guest users from initiating a login session. The guest user is BookStack's synthetic unauthenticated identity, so authenticating it would break the auth model; LoginAttemptInvalidUserException is thrown with this message.

Source

Thrown at app/Access/LoginService.php:41

    public function __construct(
        protected MfaSession $mfaSession,
        protected EmailConfirmationService $emailConfirmationService,
        protected SocialDriverManager $socialDriverManager,
    ) {
    }

    /**
     * Log the given user into the system.
     * Will start a login of the given user but will prevent if there's
     * a reason to (MFA or Unconfirmed Email).
     * Returns a boolean to indicate the current login result.
     *
     * @throws StoppedAuthenticationException|LoginAttemptInvalidUserException
     */
    public function login(User $user, string $method, bool $remember = false): void
    {
        if ($user->isGuest()) {
            throw new LoginAttemptInvalidUserException('Login not allowed for guest user');
        }

        if ($this->awaitingEmailConfirmation($user) || $this->needsMfaVerification($user)) {
            $this->setLastLoginAttemptedForUser($user, $method, $remember);

            throw new StoppedAuthenticationException($user, $this);
        }

        $this->clearLastLoginAttempted();
        auth()->login($user, $remember);
        Activity::add(ActivityType::AUTH_LOGIN, "{$method}; {$user->logDescriptor()}");
        Theme::dispatch(ThemeEvents::AUTH_LOGIN, $method, $user);

        // Authenticate on all session guards if a likely admin
        if ($user->can(Permission::UsersManage) && $user->can(Permission::UserRolesManage)) {
            $guards = ['standard', 'ldap', 'saml2', 'oidc'];
            foreach ($guards as $guard) {
                auth($guard)->login($user);

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Check the caller to see why the User object being passed is the guest user (isGuest() true)
  2. Fix the user lookup so real credentials map to a real user, not the guest record
  3. Guard calling code: skip or reject login attempts when $user->isGuest() before invoking login()
  4. Ensure no seeded/imported user shares the guest user's identity (system guest id/email)

Example fix

// before
$user = User::query()->find($request->get('user_id', 0));
$loginService->login($user, 'standard');
// after
$user = User::query()->findOrFail($request->get('user_id'));
if ($user->isGuest()) {
    return redirect('/login')->with('error', 'Invalid account');
}
$loginService->login($user, 'standard');
Defensive patterns

Strategy: type-guard

Validate before calling

if ($user->isGuest()) {
    return redirect('/login')->withErrors(['email' => 'Invalid account']);
}
$loginService->login($user, 'standard');

Type guard

function isRealUser(?User $user): bool {
    return $user !== null && !$user->isGuest() && $user->exists;
}

Try / catch

try {
    $loginService->login($user, $method);
} catch (LoginAttemptInvalidUserException $e) {
    Log::warning('Login attempted for guest/invalid user', ['user_id' => $user->id ?? null]);
    abort(401, $e->getMessage());
}

Prevention

When it happens

Trigger: login($user, $method) called (directly or via attempt()/reattemptLoginFor()) with a User whose isGuest() returns true — e.g. passing the guest user model (id 0 / system guest) into the login flow, or a lookup that wrongly resolves to the guest account.

Common situations: Custom auth driver or plugin code that resolves a user by id/email and accidentally matches the guest record; importing or seeding users that collide with the guest user; automation scripts calling the login service with a default-constructed user.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/7bf3d147bcb34809. Report an issue: GitHub.