mattermost-community/focalboard · error

cannot save member %s while inserting board %s: %w

Error message

cannot save member %s while inserting board %s: %w

What it means

Wraparound error in SQLStore.InsertBoardWithAdmin (server/services/store/sqlstore/board.go:496). After inserting the board row within the same transaction, the store saves the admin board-member row via saveMember(db, bm). If that insert fails, the whole board creation is aborted and the underlying DB error is wrapped with the user ID and board ID so the caller knows which member/board pair failed.

Source

Thrown at server/services/store/sqlstore/board.go:496

	return s.deleteBlockChildren(db, boardID, "", userID)
}

func (s *SQLStore) insertBoardWithAdmin(db sq.BaseRunner, board *model.Board, userID string) (*model.Board, *model.BoardMember, error) {
	newBoard, err := s.insertBoard(db, board, userID)
	if err != nil {
		return nil, nil, err
	}

	bm := &model.BoardMember{
		BoardID:      newBoard.ID,
		UserID:       newBoard.CreatedBy,
		SchemeAdmin:  true,
		SchemeEditor: true,
	}

	nbm, err := s.saveMember(db, bm)
	if err != nil {
		return nil, nil, fmt.Errorf("cannot save member %s while inserting board %s: %w", bm.UserID, bm.BoardID, err)
	}

	return newBoard, nbm, nil
}

func (s *SQLStore) saveMember(db sq.BaseRunner, bm *model.BoardMember) (*model.BoardMember, error) {
	queryValues := map[string]interface{}{
		"board_id":         bm.BoardID,
		"user_id":          bm.UserID,
		"roles":            "",
		"scheme_admin":     bm.SchemeAdmin,
		"scheme_editor":    bm.SchemeEditor,
		"scheme_commenter": bm.SchemeCommenter,
		"scheme_viewer":    bm.SchemeViewer,
	}

	oldMember, err := s.getMemberForBoard(db, bm.BoardID, bm.UserID)
	if err != nil && !model.IsErrNotFound(err) {

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Inspect the wrapped underlying error (%w cause) in logs to identify the exact DB failure (duplicate key, FK violation, connection error).
  2. Query the board_members table for existing rows with the offending board_id/user_id and delete stale duplicates before retrying.
  3. Verify the user and board rows exist and the DB schema matches the expected version (run migrations).
  4. Retry the board creation; if persistent, check DB connectivity, pool limits, and lock contention.
  5. Upgrade/repair the plugin database schema if the error is a missing-column or constraint error after a version change.

Example fix

// before
nbm, err := s.saveMember(db, bm)
if err != nil {
	return nil, nil, fmt.Errorf("cannot save member %s while inserting board %s: %w", bm.UserID, bm.BoardID, err)
}
// after
nbm, err := s.saveMember(db, bm)
if err != nil {
	if errors.Is(err, sql.ErrNoRows) {
		return nil, nil, fmt.Errorf("user %s not found while inserting board %s", bm.UserID, bm.BoardID)
	}
	return nil, nil, fmt.Errorf("cannot save member %s while inserting board %s: %w", bm.UserID, bm.BoardID, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

const ok, err := db.Ping(); if err != nil || !ok { /* don't attempt board creation */ }

Type guard

func isSaveMemberError(err error) (*model.BoardMember, bool) {
	var target error
	if errors.As(err, &target) && strings.Contains(target.Error(), "cannot save member") {
		return nil, true
	}
	return nil, false
}

Try / catch

nbm, err := store.InsertBoardWithAdmin(board, bm)
if err != nil {
	if strings.Contains(err.Error(), "cannot save member") {
		// inspect errors.Unwrap(err) for duplicate key / FK violation, clean up board_members, then retry
	}
	return err
}

Prevention

When it happens

Trigger: Calling InsertBoardWithAdmin (directly or via board creation API) when the board_members insert fails: e.g. duplicate (board_id, user_id) primary key on the board_members table, foreign-key violation because the user or board row is not visible to the transaction, schema mismatch after a partial migration, or DB connectivity/constraint failure during saveMember.

Common situations: Duplicated board-member rows left by an earlier failed import or migration; creating boards for users that were deleted concurrently; running an old schema against newer app code (missing columns/constraints on board_members); database outages or connection pool exhaustion mid-request.

Related errors


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