mattermost-community/focalboard · error
cannot leave a board with no admins
Error message
cannot leave a board with no admins
What it means
ErrBoardMemberIsLastAdmin is returned when a board membership operation would remove the last admin of a board. Boards must retain at least one admin member, so UpdateBoardMember (demoting to a lower role) and DeleteBoardMember (leaving/removal) check this and reject the change with this sentinel error. IsErrBadRequest maps it to HTTP 400.
Source
Thrown at server/model/error.go:24
"fmt"
"net/http"
"strings"
mmModel "github.com/mattermost/mattermost/server/public/model"
pluginapi "github.com/mattermost/mattermost/server/public/pluginapi"
)
var (
ErrViewsLimitReached = errors.New("views limit reached for board")
ErrPatchUpdatesLimitedCards = errors.New("patch updates cards that are limited")
ErrInsufficientLicense = errors.New("appropriate license required")
ErrCategoryPermissionDenied = errors.New("category doesn't belong to user")
ErrCategoryDeleted = errors.New("category is deleted")
ErrBoardMemberIsLastAdmin = errors.New("cannot leave a board with no admins")
ErrRequestEntityTooLarge = errors.New("request entity too large")
ErrInvalidBoardSearchField = errors.New("invalid board search field")
)
// ErrNotFound is an error type that can be returned by store APIs
// when a query unexpectedly fetches no records.
type ErrNotFound struct {
entity string
}
// NewErrNotFound creates a new ErrNotFound instance.
func NewErrNotFound(entity string) *ErrNotFound {
return &ErrNotFound{
entity: entity,
}
}View on GitHub (pinned to a84bbb65e3)
Solutions
- Promote another member to Admin first, then leave/demote the original admin
- Have a system admin reassign board ownership via admin APIs
- Use the UI's ownership transfer flow which handles the handoff
Example fix
// before
err := app.DeleteBoardMember(boardID, lastAdminUserID)
// after
err := app.UpdateBoardMember(boardID, newAdminUserID, model.BoardRoleAdmin)
if err != nil { return err }
err = app.DeleteBoardMember(boardID, lastAdminUserID) Defensive patterns
Strategy: type-guard
Validate before calling
members, err := app.GetMembersForBoard(boardID)
if err == nil && countAdmins(members) <= 1 && memberIsLastAdmin {
// block the leave/demote and prompt ownership transfer
} Type guard
func isLastAdminErr(err error) bool {
return errors.Is(err, model.ErrBoardMemberIsLastAdmin)
} Try / catch
err := app.DeleteBoardMember(boardID, userID)
if errors.Is(err, model.ErrBoardMemberIsLastAdmin) {
// ask user to promote another member first
} Prevention
- Promote a successor admin before leaving/removing admins
- Check admin count in offboarding scripts
- Expose ownership-transfer UI to the sole admin
When it happens
Trigger: The last board admin calls leave board; DeleteBoardMember removes the only member with the Admin role; UpdateBoardMember changes the sole Admin's role to Editor/Viewer.
Common situations: Sole board owner leaving a team and trying to hand off incorrectly; bulk offboarding scripts that remove the last admin; role-change UI on the only admin row.
Related errors
- category doesn't belong to user
- mention not permitted
- block fields size limit exceeded
- at least one board is required
- at least one block is required
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/f096256f19453d37.
Report an issue: GitHub.