{"record":{"id":"767456050d539471","repo":"mattermost-community/focalboard","slug":"cannot-create-card-w","errorCode":null,"errorMessage":"cannot create card: %w","messagePattern":"cannot create card: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/app/cards.go","lineNumber":29,"sourceCode":")\n\nfunc (a *App) CreateCard(card *model.Card, boardID string, userID string, disableNotify bool) (*model.Card, error) {\n\t// Convert the card struct to a block and insert the block.\n\tnow := utils.GetMillis()\n\n\tcard.ID = utils.NewID(utils.IDTypeCard)\n\tcard.BoardID = boardID\n\tcard.CreatedBy = userID\n\tcard.ModifiedBy = userID\n\tcard.CreateAt = now\n\tcard.UpdateAt = now\n\tcard.DeleteAt = 0\n\n\tblock := model.Card2Block(card)\n\n\tnewBlocks, err := a.InsertBlocksAndNotify([]*model.Block{block}, userID, disableNotify)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot create card: %w\", err)\n\t}\n\n\tnewCard, err := model.Block2Card(newBlocks[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newCard, nil\n}\n\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","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/app/cards.go#L11-L47","documentation":"CreateCard converts the Card model into a Block and inserts it via InsertBlocksAndNotify. This error wraps any failure of that insertion (validation, store write, or notification pipeline) under the message 'cannot create card'. The card is not created when this is returned.","triggerScenarios":"App.CreateCard failing inside InsertBlocksAndNotify: invalid card fields (empty title/boardID, bad parentID), block validation failure, store insert error, or an error thrown by the block-change notification hook (websocket/plugin subscribers).","commonSituations":"API clients posting cards missing required fields; database outages; a plugin's WatchBlockChange hook rejecting the insert; board ID pointing to a deleted board.","solutions":["Inspect the wrapped cause from errors.Unwrap — fix the underlying validation or store error it names.","Validate the card (Title, BoardID/ParentID set, valid types) before calling CreateCard.","Confirm the target board exists and the user has permission to add blocks to it.","Check plugin/websocket notification hooks for panics or rejections if validation and store are fine."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func validateCard(c *model.Card) error {\n    if c == nil {\n        return errors.New(\"card is nil\")\n    }\n    if strings.TrimSpace(c.Title) == \"\" {\n        return errors.New(\"card title is required\")\n    }\n    if c.BoardID == \"\" {\n        return errors.New(\"card BoardID is required\")\n    }\n    return nil\n}\n// call validateCard(card) before app.CreateCard","typeGuard":"func isValidCard(c *model.Card) bool {\n    return c != nil && strings.TrimSpace(c.Title) != \"\" && c.BoardID != \"\"\n}","tryCatchPattern":"card, err := app.CreateCard(card, userID, false)\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot create card\") {\n        return fmt.Errorf(\"card creation rejected: %w\", errors.Unwrap(err))\n    }\n    return err\n}","preventionTips":["Validate card fields (title, boardID) client- and server-side before insert.","Confirm the target board exists and permits block inserts.","Unwrap the error to find whether validation, store, or a notification hook failed.","Keep plugin WatchBlockChange hooks defensive (no panics, no hard rejections)."],"tags":["card","insert","wrapped-error","validation"],"backgroundTag":"block-insert-failed","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}