{"record":{"id":"612c525466037870","repo":"mattermost-community/focalboard","slug":"patch-updates-cards-that-are-limited","errorCode":null,"errorMessage":"patch updates cards that are limited","messagePattern":"patch updates cards that are limited","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/model/error.go","lineNumber":17,"sourceCode":"package model\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\tmmModel \"github.com/mattermost/mattermost/server/public/model\"\n\n\tpluginapi \"github.com/mattermost/mattermost/server/public/pluginapi\"\n)\n\nvar (\n\tErrViewsLimitReached        = errors.New(\"views limit reached for board\")\n\tErrPatchUpdatesLimitedCards = errors.New(\"patch updates cards that are limited\")\n\n\tErrInsufficientLicense = errors.New(\"appropriate license required\")\n\n\tErrCategoryPermissionDenied = errors.New(\"category doesn't belong to user\")\n\tErrCategoryDeleted          = errors.New(\"category is deleted\")\n\n\tErrBoardMemberIsLastAdmin = errors.New(\"cannot leave a board with no admins\")\n\n\tErrRequestEntityTooLarge = errors.New(\"request entity too large\")\n\n\tErrInvalidBoardSearchField = errors.New(\"invalid board search field\")\n)\n\n// ErrNotFound is an error type that can be returned by store APIs\n// when a query unexpectedly fetches no records.\ntype ErrNotFound struct {\n\tentity string\n}","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/model/error.go#L1-L35","documentation":"ErrPatchUpdatesLimitedCards is returned when a card patch (partial update) would modify cards that are restricted under the current license tier. Like the views limit, this is a licensing guard: unlicensed installs only allow limited card operations, and a patch touching those protected fields/cards is rejected wholesale.","triggerScenarios":"Sending PATCH /api/v1/boards/{boardID}/blocks/{blockID} (or MoveContentBlock) against a card that is limited on an unlicensed install; calling MoveContentBlock whose destination patch updates limited cards.","commonSituations":"Free-tier installs after the cards feature became partially paid; API scripts that bulk-patch card properties; drag-and-drop moves in the UI that internally patch cards.","solutions":["Obtain a license covering full Boards card functionality","Limit the patch to fields not restricted by the license","Move the card without patching restricted properties, or restructure the workflow"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if !hasValidLicense() && patchTouchesLimitedCards(patch) {\n    // reject or trim the patch client-side before sending\n}","typeGuard":"func isLimitedCardsErr(err error) bool {\n    return errors.Is(err, model.ErrPatchUpdatesLimitedCards)\n}","tryCatchPattern":"err := app.PatchBlock(boardID, blockID, patch)\nif errors.Is(err, model.ErrPatchUpdatesLimitedCards) {\n    // fall back to a limited patch or notify the user\n}","preventionTips":["Detect license state before enabling bulk card edits","Keep patches minimal and split out restricted fields","Test card workflows on an unlicensed install"],"tags":["go","licensing","cards","patch"],"backgroundTag":"license-limit-reached","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}