{"record":{"id":"b46d48e7d16c223b","repo":"mattermost-community/focalboard","slug":"block2card-fail-w","errorCode":null,"errorMessage":"Block2Card fail: %w","messagePattern":"Block2Card fail: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/app/cards.go","lineNumber":57,"sourceCode":"\nfunc (a *App) GetCardsForBoard(boardID string, page int, perPage int) ([]*model.Card, error) {\n\topts := model.QueryBlocksOptions{\n\t\tBoardID:   boardID,\n\t\tBlockType: model.TypeCard,\n\t\tPage:      page,\n\t\tPerPage:   perPage,\n\t}\n\n\tblocks, err := a.store.GetBlocks(opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcards := make([]*model.Card, 0, len(blocks))\n\tfor _, blk := range blocks {\n\t\tb := blk\n\t\tif card, err := model.Block2Card(b); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Block2Card fail: %w\", err)\n\t\t} else {\n\t\t\tcards = append(cards, card)\n\t\t}\n\t}\n\treturn cards, nil\n}\n\nfunc (a *App) PatchCard(cardPatch *model.CardPatch, cardID string, userID string, disableNotify bool) (*model.Card, error) {\n\tblockPatch, err := model.CardPatch2BlockPatch(cardPatch)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewBlock, err := a.PatchBlockAndNotify(cardID, blockPatch, userID, disableNotify)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot patch card %s: %w\", cardID, err)\n\t}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/app/cards.go#L39-L75","documentation":"GetCardsForBoard fetches all card blocks of a board and converts each Block back into a Card with model.Block2Card. If any single block fails conversion (e.g. it is not a card-type block or its fields do not unmarshal into Card), this error wraps the cause and the whole call fails, returning no cards.","triggerScenarios":"App.GetCardsForBoard on a board whose block list contains a block that cannot be converted: wrong block type slipped into card-type filtering, corrupted/legacy block JSON missing required card fields, or schema drift after version upgrades.","commonSituations":"Boards imported from older Focalboard versions with legacy block payloads; manual DB edits producing invalid card blocks; a bug storing non-card blocks under card queries; corrupted fields after failed migrations.","solutions":["Unwrap the error to identify which block/field failed conversion; fix or remove the malformed block row.","Skip-and-log malformed blocks instead of failing the whole listing (requires a source change to continue the loop on error).","Verify no non-card block types are being returned by the store query filtering.","Run a data-integrity check/migration if boards were imported from an older version."],"exampleFix":"// before\nif card, err := model.Block2Card(b); err != nil {\n    return nil, fmt.Errorf(\"Block2Card fail: %w\", err)\n} else {\n    cards = append(cards, card)\n}\n// after\ncard, err := model.Block2Card(b)\nif err != nil {\n    a.logger.Warn(\"skipping invalid card block\", mlog.String(\"blockID\", b.ID), mlog.Err(err))\n    continue\n}\ncards = append(cards, card)","handlingStrategy":"try-catch","validationCode":"// ensure blocks are card-typed before conversion\nfor _, blk := range blocks {\n    if blk.Type != model.TypeCard {\n        return fmt.Errorf(\"non-card block %s (%s) in card query\", blk.ID, blk.Type)\n    }\n}","typeGuard":"func isCardBlock(b *model.Block) bool {\n    return b != nil && b.Type == model.TypeCard\n}","tryCatchPattern":"cards, err := app.GetCardsForBoard(boardID, viewID)\nif err != nil {\n    if strings.Contains(err.Error(), \"Block2Card fail\") {\n        return fmt.Errorf(\"board %s contains a malformed card block: %w\", boardID, errors.Unwrap(err))\n    }\n    return err\n}","preventionTips":["Keep block payloads schema-valid across version upgrades; run migrations on upgrade.","Never hand-edit block rows in the database.","Filter strictly on card block type before conversion.","On import, validate legacy blocks and repair or drop non-conforming ones."],"tags":["card","conversion","data-integrity","wrapped-error"],"backgroundTag":"block-conversion-failed","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}