mattermost-community/focalboard · error

insertBoard error occurred while inserting board %s: %w

Error message

insertBoard error occurred while inserting board %s: %w

What it means

When no existing board shares the ID, insertBoard performs the INSERT into the boards table; a failed Exec raises this wrapped error. It is the plain-insert arm of the upsert logic and wraps the driver's error, so the root cause (unique constraint, connection, type mismatch) must be read from %w.

Source

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

			Set("template_version", board.TemplateVersion).
			Set("properties", propertiesBytes).
			Set("card_properties", cardPropertiesBytes).
			Set("update_at", board.UpdateAt).
			Set("delete_at", board.DeleteAt)

		if _, err := query.Exec(); err != nil {
			s.logger.Error(`InsertBoard error occurred while updating existing board`, mlog.String("boardID", board.ID), mlog.Err(err))
			return nil, fmt.Errorf("insertBoard error occurred while updating existing board %s: %w", board.ID, err)
		}
	} else {
		board.CreatedBy = userID
		board.CreateAt = now
		insertQueryValues["created_by"] = board.CreatedBy
		insertQueryValues["create_at"] = board.CreateAt

		query := insertQuery.SetMap(insertQueryValues).Into(s.tablePrefix + "boards")
		if _, err := query.Exec(); err != nil {
			return nil, fmt.Errorf("insertBoard error occurred while inserting board %s: %w", board.ID, err)
		}
	}

	// writing board history
	query := insertQuery.SetMap(insertQueryValues).Into(s.tablePrefix + "boards_history")
	if _, err := query.Exec(); err != nil {
		s.logger.Error("failed to insert board history", mlog.String("board_id", board.ID), mlog.Err(err))
		return nil, fmt.Errorf("failed to insert board %s history: %w", board.ID, err)
	}

	return board, nil
}

func (s *SQLStore) patchBoard(db sq.BaseRunner, boardID string, boardPatch *model.BoardPatch, userID string) (*model.Board, error) {
	existingBoard, err := s.getBoard(db, boardID)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Read the wrapped driver error to distinguish constraint vs connection vs schema issues
  2. Run database migrations to ensure the boards schema matches your server version
  3. Add an idempotent retry with a NEW board ID if a duplicate-key race is suspected
  4. Verify field lengths/types conform to the schema (trim overly long titles/channel names)

Example fix

// before
board.ID = someFixedID // race-prone across replicas
// after
if board.ID == "" {
    board.ID = utils.NewID() // unique per insert
}
_, err := insertBoard(board)
Defensive patterns

Strategy: validation

Validate before calling

func boardInsertable(b *model.Board) error {
    if b.ID == "" { return fmt.Errorf("board ID required") }
    if len(b.Title) > 255 { return fmt.Errorf("title too long") }
    return nil
}

Try / catch

board, err := store.InsertBoard(board, userID)
if err != nil && strings.Contains(err.Error(), "error occurred while inserting board") {
    if strings.Contains(err.Error(), "Duplicate") {
        board.ID = utils.NewID() // regenerate on rare duplicate-key race
        board, err = store.InsertBoard(board, userID)
    }
}

Prevention

When it happens

Trigger: InsertBoard/patchBoard/createBoardsAndBlocks/insertBoardWithAdmin inserting a new board where Exec fails — e.g. duplicate ID raced with another insert after the existence check, invalid column values, or DB connection failure.

Common situations: Two concurrent InsertBoard calls with the same generated ID (rare); schema drift (missing columns after upgrade without migration); values exceeding column sizes (e.g. very long titles/fields); MySQL strict mode rejecting zero dates.

Related errors


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