{"record":{"id":"469c408895ea2ab0","repo":"mattermost-community/focalboard","slug":"could-not-get-blocks-history-descendants-for-board","errorCode":null,"errorMessage":"could not get blocks history descendants for board: %w","messagePattern":"could not get blocks history descendants for board: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/app/boards.go","lineNumber":131,"sourceCode":"\t\treturn 0, \"\", fmt.Errorf(\"history not found for board: %w\", err)\n\t}\n\n\tvar timestamp int64\n\tmodifiedBy := board.ModifiedBy\n\tif latest {\n\t\ttimestamp = board.UpdateAt\n\t} else {\n\t\ttimestamp = board.CreateAt\n\t}\n\n\t// use block_history to fetch blocks in case they were deleted and no longer exist in blocks table.\n\topts := model.QueryBlockHistoryOptions{\n\t\tLimit:      1,\n\t\tDescending: latest,\n\t}\n\tblocks, err := a.store.GetBlockHistoryDescendants(boardID, opts)\n\tif err != nil {\n\t\treturn 0, \"\", fmt.Errorf(\"could not get blocks history descendants for board: %w\", err)\n\t}\n\tif len(blocks) > 0 {\n\t\t// Compare the board history info with the descendant block info, if it exists\n\t\tblock := blocks[0]\n\t\tif latest && block.UpdateAt > timestamp {\n\t\t\ttimestamp = block.UpdateAt\n\t\t\tmodifiedBy = block.ModifiedBy\n\t\t} else if !latest && block.CreateAt < timestamp {\n\t\t\ttimestamp = block.CreateAt\n\t\t\tmodifiedBy = block.ModifiedBy\n\t\t}\n\t}\n\treturn timestamp, modifiedBy, nil\n}\n\nfunc (a *App) setBoardCategoryFromSource(sourceBoardID, destinationBoardID, userID, teamID string, asTemplate bool) error {\n\t// find source board's category ID for the user\n\tuserCategoryBoards, err := a.GetUserCategoryBoards(userID, teamID)","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/app/boards.go#L113-L149","documentation":"After reading board history, getBoardDescendantModifiedInfo queries the newest history entry among all descendant blocks via store.GetBlockHistoryDescendants. This error wraps a failure of that store call while computing the board's effective last-modified timestamp.","triggerScenarios":"GetBoardMetadata on a board with many descendant blocks where the store query fails: database timeout, index/collection missing for block history, or oversized descendant query exceeding DB limits.","commonSituations":"Very large boards causing slow/failed descendant history queries; block-history collections dropped or not migrated; transient database outages during metadata loads.","solutions":["Inspect the wrapped store error; check DB logs for query timeouts on block history.","Confirm block-history storage (indexes/collections) exists and is migrated.","Retry transient failures; consider caching metadata for large boards.","Verify boardID is a valid board with existing descendants."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if _, err := app.GetBoard(boardID); err != nil {\n    return fmt.Errorf(\"board %s must exist before descendant history query\", boardID)\n}","typeGuard":null,"tryCatchPattern":"meta, err := app.GetBoardMetadata(boardID, latest)\nif err != nil {\n    if strings.Contains(err.Error(), \"could not get blocks history descendants\") && isTransient(err) {\n        return retryWithBackoff(func() error { _, err = app.GetBoardMetadata(boardID, latest); return err })\n    }\n    return err\n}","preventionTips":["Index block-history by boardID/rootID so descendant queries stay fast on large boards.","Split very large boards; descendant history queries scale with block count.","Confirm block-history storage exists after migrations or store swaps."],"tags":["history","blocks","store","wrapped-error"],"backgroundTag":"history-lookup-failed","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}