mattermost-community/focalboard · error
cannot fetch board %s for DuplicateBlock: %w
Error message
cannot fetch board %s for DuplicateBlock: %w
What it means
DuplicateBlock fetches the owning board via GetBoard before duplicating a block. This message is returned when GetBoard succeeds (err == nil) but the returned board is nil, meaning the boardID does not resolve to a board. Note the format verb wraps a nil error here, so the trailing ': %!w(<nil>)' may appear in the rendered message; the meaningful part is 'cannot fetch board <id> for DuplicateBlock'.
Source
Thrown at server/app/blocks.go:37
if blockType != "" && parentID != "" {
return a.store.GetBlocksWithParentAndType(boardID, parentID, blockType)
}
if blockType != "" {
return a.store.GetBlocksWithType(boardID, blockType)
}
return a.store.GetBlocksWithParent(boardID, parentID)
}
func (a *App) DuplicateBlock(boardID string, blockID string, userID string, asTemplate bool) ([]*model.Block, error) {
board, err := a.GetBoard(boardID)
if err != nil {
return nil, err
}
if board == nil {
return nil, fmt.Errorf("cannot fetch board %s for DuplicateBlock: %w", boardID, err)
}
blocks, err := a.store.DuplicateBlock(boardID, blockID, userID, asTemplate)
if err != nil {
return nil, err
}
err = a.CopyAndUpdateCardFiles(boardID, userID, blocks, asTemplate)
if err != nil {
return nil, err
}
a.blockChangeNotifier.Enqueue(func() error {
for _, block := range blocks {
a.wsAdapter.BroadcastBlockChange(board.TeamID, block)
}
return nil
})View on GitHub (pinned to a84bbb65e3)
Solutions
- Verify the boardID exists via App.GetBoard(boardID) before calling DuplicateBlock.
- Refresh the client's board list; the board was likely deleted or the ID is stale.
- Fix the source bug: this branch wraps a nil err; it should return a sentinel like model.ErrBoardNotFound (or `errors.New` with the boardID) instead of %w on nil.
- If the ID came from an API payload, validate it against the team's board list server-side.
Example fix
// before
if board == nil {
return nil, fmt.Errorf("cannot fetch board %s for DuplicateBlock: %w", boardID, err)
}
// after
if board == nil {
return nil, fmt.Errorf("cannot fetch board %s for DuplicateBlock: %w", boardID, model.ErrBoardNotFound)
} Defensive patterns
Strategy: validation
Validate before calling
board, err := app.GetBoard(boardID)
if err != nil || board == nil {
return fmt.Errorf("board %s not available for duplication", boardID)
}
// safe to call app.DuplicateBlock(boardID, blockID, userID, asTemplate) Type guard
func boardExists(b *model.Board) bool { return b != nil && b.ID != "" } Try / catch
blocks, err := app.DuplicateBlock(boardID, blockID, userID, asTemplate)
if err != nil {
return fmt.Errorf("duplicate block failed (is board %s still valid?): %w", boardID, err)
} Prevention
- Re-fetch the board immediately before duplication instead of trusting a cached ID.
- Handle board-deleted events in the client to invalidate stale boardIDs.
- Watch for the '%!w(<nil>)' artifact in logs — it signals this nil-wrap branch, i.e. a missing board rather than a store failure.
When it happens
Trigger: Calling App.DuplicateBlock(boardID, blockID, userID, asTemplate) with a boardID that does not exist in the store, or a board that was deleted concurrently, or a board the store layer filters out (e.g. soft-deleted/permission-filtered), so GetBoard returns (nil, nil).
Common situations: Client caches a stale boardID after the board was deleted by another user; test fixtures use a fabricated board ID without creating the board; race between listing boards and duplicating a block in one.
Related errors
- history not found for board: %w
- %w userID: %s
- not a card block
- category is deleted
- cannot get board %s: %w
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/73040486c289bd4a.
Report an issue: GitHub.