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

  1. Promote another member to Admin first, then leave/demote the original admin
  2. Have a system admin reassign board ownership via admin APIs
  3. 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

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


AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30). Data as JSON: /api/errors/f096256f19453d37. Report an issue: GitHub.