BookStackApp/BookStack · error · NotifyException
errors.users_cannot_delete_guest
Error message
errors.users_cannot_delete_guest
What it means
ensureDeletable() also throws NotifyException when the target user is the system 'guest' user (system_name === 'public'). The guest user is an internal representation of unauthenticated access and must always exist, so BookStack blocks its deletion with errors.users_cannot_delete_guest and redirects to the user's edit page.
Source
Thrown at app/Users/UserRepo.php:257
foreach ($columns as $column) {
DB::table($table)
->where($column, '=', $user->id)
->update([$column => null]);
}
}
}
/**
* @throws NotifyException
*/
protected function ensureDeletable(User $user): void
{
if ($this->isOnlyAdmin($user)) {
throw new NotifyException(trans('errors.users_cannot_delete_only_admin'), $user->getEditUrl());
}
if ($user->system_name === 'public') {
throw new NotifyException(trans('errors.users_cannot_delete_guest'), $user->getEditUrl());
}
}
/**
* Migrate ownership of items in the system from one user to another.
*/
protected function migrateOwnership(User $fromUser, User|null $toUser): void
{
$newOwnerValue = $toUser ? $toUser->id : null;
DB::table('entities')
->where('owned_by', '=', $fromUser->id)
->update(['owned_by' => $newOwnerValue]);
}
/**
* Get an avatar image for a user and set it as their avatar.
* Returns early if avatars disabled or not set in config.
*/View on GitHub (pinned to 18f8469a1c)
Solutions
- Exclude users where system_name === 'public' from deletion flows/UI
- Filter guest users out of bulk-delete scripts before calling destroy
- Treat NotifyException as a redirect-with-message, not a crash — catch it in API wrappers and return a 4xx with the translated message
- Restore accidentally modified guest records from backup / reset system_name
Example fix
// before
foreach ($users as $u) { $this->userRepo->destroy($u); }
// after
foreach ($users as $u) {
if ($u->system_name !== 'public') { $this->userRepo->destroy($u); }
} Defensive patterns
Strategy: validation
Validate before calling
// Skip the system guest user
if ($user->system_name === 'public') {
return; // guest user cannot be deleted
}
$userRepo->destroy($user); Type guard
function isSystemUser(\BookStack\Users\User $u): bool {
return $u->system_name === 'public';
} Try / catch
try {
$userRepo->destroy($user);
} catch (\BookStack\Exceptions\NotifyException $e) {
return redirect($user->getEditUrl())->with('error', $e->getMessage());
} Prevention
- Filter users with system_name set (e.g. 'public') from delete UIs and scripts
- Query user lists excluding system users: whereNull('system_name')
- Never hardcode 'delete all users' maintenance jobs
- Handle NotifyException gracefully in API wrappers
When it happens
Trigger: UserRepo::destroy invoked with the user whose system_name property equals 'public' — BookStack's built-in guest/public visibility user.
Common situations: Admins browsing the users list attempting to delete the guest entry; scripted cleanups that iterate over all users and hit the guest record; API-driven user management lacking a system-user filter.
Related errors
- errors.users_cannot_delete_only_admin
- errors.role_cannot_remove_only_admin
- errors.chapter_not_found
- errors.page_not_found
- User does not have permission to create a chapter within the
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/a49d7fdb73c319bb.
Report an issue: GitHub.