mattermost-community/focalboard · error

could not patch file IDs while duplicating board %s: %w

Error message

could not patch file IDs while duplicating board %s: %w

What it means

DuplicateBoard duplicates a board (optionally as a template) into another team. After copying blocks it calls CopyAndUpdateCardFiles to patch file IDs on duplicated cards; if that fails, this error wraps the cause and the just-created duplicate board/blocks are deleted as rollback. The message includes the original boardID for correlation.

Source

Thrown at server/app/boards.go:194

	// now that we have source board's category,
	// we send destination board to the same category
	return a.AddUpdateUserCategoryBoard(teamID, userID, destinationCategoryID, []string{destinationBoardID})
}

func (a *App) DuplicateBoard(boardID, userID, toTeam string, asTemplate bool) (*model.BoardsAndBlocks, []*model.BoardMember, error) {
	bab, members, err := a.store.DuplicateBoard(boardID, userID, toTeam, asTemplate)
	if err != nil {
		return nil, nil, err
	}

	// copy any file attachments from the duplicated blocks.
	err = a.CopyAndUpdateCardFiles(boardID, userID, bab.Blocks, asTemplate)
	if err != nil {
		dbab := model.NewDeleteBoardsAndBlocksFromBabs(bab)
		if dErr := a.store.DeleteBoardsAndBlocks(dbab, userID); dErr != nil {
			a.logger.Error("Cannot delete board after duplication error when updating block's file info", mlog.String("boardID", bab.Boards[0].ID), mlog.Err(dErr))
		}
		return nil, nil, fmt.Errorf("could not patch file IDs while duplicating board %s: %w", boardID, err)
	}

	if !asTemplate {
		for _, board := range bab.Boards {
			if categoryErr := a.setBoardCategoryFromSource(boardID, board.ID, userID, toTeam, asTemplate); categoryErr != nil {
				return nil, nil, categoryErr
			}
		}
	}

	a.blockChangeNotifier.Enqueue(func() error {
		teamID := ""
		for _, board := range bab.Boards {
			teamID = board.TeamID
			a.wsAdapter.BroadcastBoardChange(teamID, board)
		}
		for _, block := range bab.Blocks {
			blk := block

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Check the wrapped cause — most often file-store connectivity or credentials; fix FileSettings and retry the duplication.
  2. Verify the source board's card files exist in the file store before duplicating.
  3. Look for the preceding log line 'Cannot delete board after duplication error...' to clean up any leftover duplicate board if rollback also failed.
  4. Ensure the storage backend has free space / network access, then repeat DuplicateBoard.
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight file store check before duplicating
for _, f := range boardCardFileIDs {
    if _, err := fileStore.Reader(f); err != nil {
        return fmt.Errorf("file %s unreadable; fix storage before duplicating board", f)
    }
}

Try / catch

newBoard, _, err := app.DuplicateBoard(board, toTeam, userID, asTemplate)
if err != nil {
    if strings.Contains(err.Error(), "could not patch file IDs") {
        // duplicate board was rolled back; check file-store config and retry
        return retryAfterStorageCheck(board.ID, userID)
    }
    return err
}

Prevention

When it happens

Trigger: App.DuplicateBoard (also invoked by createWelcomeBoard) where CopyAndUpdateCardFiles fails: file storage (S3/minio/local) unreachable, source card files missing, or the files-table update errors — right after the duplicate board blocks were inserted.

Common situations: Misconfigured FileSettings (bad S3 credentials/endpoint); orphaned file records pointing to deleted objects; network partition between app server and file store; disk full on local driver.

Related errors


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