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 := blockView on GitHub (pinned to a84bbb65e3)
Solutions
- Check the wrapped cause — most often file-store connectivity or credentials; fix FileSettings and retry the duplication.
- Verify the source board's card files exist in the file store before duplicating.
- Look for the preceding log line 'Cannot delete board after duplication error...' to clean up any leftover duplicate board if rollback also failed.
- 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
- Validate FileSettings (S3 credentials, endpoint, local driver disk space) before bulk duplication.
- Verify source card files are readable before CopyAndUpdateCardFiles runs.
- After a failure, check logs for the rollback message to ensure no duplicate board leaked.
- Monitor file-store connectivity in health checks.
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.