mattermost-community/focalboard · error
cannot get board %s: %w
Error message
cannot get board %s: %w
What it means
In getBoardForBlock, after the block is loaded, the parent board (block.BoardID) is fetched. This error wraps a failure of App.GetBoard(block.BoardID) — the board that owns the block cannot be retrieved. It indicates the board was deleted while its block still exists, or a store-level error occurred.
Source
Thrown at server/app/boards.go:85
BoardID: boardID,
DescendantFirstUpdateAt: earliestTime,
DescendantLastUpdateAt: latestTime,
CreatedBy: board.CreatedBy,
LastModifiedBy: lastModifiedBy,
}
return board, &boardMetadata, nil
}
// getBoardForBlock returns the board that owns the specified block.
func (a *App) getBoardForBlock(blockID string) (*model.Board, error) {
block, err := a.GetBlockByID(blockID)
if err != nil {
return nil, fmt.Errorf("cannot get block %s: %w", blockID, err)
}
board, err := a.GetBoard(block.BoardID)
if err != nil {
return nil, fmt.Errorf("cannot get board %s: %w", block.BoardID, err)
}
return board, nil
}
func (a *App) getBoardHistory(boardID string, latest bool) (*model.Board, error) {
opts := model.QueryBoardHistoryOptions{
Limit: 1,
Descending: latest,
}
boards, err := a.store.GetBoardHistory(boardID, opts)
if err != nil {
return nil, fmt.Errorf("could not get history for board: %w", err)
}
if len(boards) == 0 {
return nil, nil
}
View on GitHub (pinned to a84bbb65e3)
Solutions
- Unwrap and check for not-found: an orphaned block points to a deleted board — clean up or ignore the notification.
- Ensure board deletion cascades to all child blocks so this state cannot occur.
- Retry the request if the underlying cause is a transient database error.
- Audit the database for blocks whose BoardID has no matching board.
Defensive patterns
Strategy: try-catch
Validate before calling
block, err := app.GetBlockByID(blockID)
if err != nil {
return err
}
board, err := app.GetBoard(block.BoardID)
if err != nil || board == nil {
return fmt.Errorf("orphaned block %s: board %s missing", blockID, block.BoardID)
} Type guard
func hasValidBoard(b *model.Block, board *model.Board) bool {
return b != nil && board != nil && board.ID == b.BoardID
} Try / catch
board, err := app.getBoardForBlock(blockID)
if err != nil {
var nf *NotFoundError
if errors.As(err, &nf) {
return nil // parent board deleted; skip notification
}
return err
} Prevention
- Ensure board deletion cascades to child blocks so orphan blocks cannot exist.
- Run periodic integrity checks for blocks referencing missing boards.
- Retry only on transient store errors, not on not-found.
When it happens
Trigger: notifySubscriptionChanged processes a block whose parent board no longer exists (orphaned block, e.g. board deleted without cascading blocks, or history/orphan rows), or the store returns an error for the board lookup.
Common situations: Data inconsistency after partial board deletion; restore-from-backup scenarios leaving orphan blocks; database outages affecting board reads.
Related errors
- cannot get block %s: %w
- could not get history for board: %w
- %w userID: %s
- cannot fetch board %s for DuplicateBlock: %w
- could not get blocks history descendants for board: %w
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/f5088f060a7c3abf.
Report an issue: GitHub.