{"record":{"id":"a978268805c48e30","repo":"siyuan-note/siyuan","slug":"view-state-patch-is-too-large","errorCode":null,"errorMessage":"view state patch is too large","messagePattern":"view state patch is too large","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/view_state.go","lineNumber":105,"sourceCode":"\t\treturn nil, errors.New(\"view state patch contains too many entries\")\n\t}\n\tfor valueKey := range values {\n\t\tif err = validateViewStateDataKey(valueKey); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfor _, removeKey := range removeKeys {\n\t\tif err = validateViewStateDataKey(removeKey); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tpatch := &viewStatePatch{Values: values, RemoveKeys: removeKeys}\n\tpatchData, marshalErr := gulu.JSON.MarshalJSON(patch)\n\tif nil != marshalErr {\n\t\treturn nil, marshalErr\n\t}\n\tif maxViewStatePatchBytes < len(patchData) {\n\t\treturn nil, errors.New(\"view state patch is too large\")\n\t}\n\t// 后续合并使用序列化快照，避免调用方在请求执行期间继续修改嵌套值。\n\tnormalizedPatch := &viewStatePatch{}\n\tif err = gulu.JSON.UnmarshalJSON(patchData, &normalizedPatch); nil != err {\n\t\treturn nil, err\n\t}\n\tvalues = normalizedPatch.Values\n\tremoveKeys = normalizedPatch.RemoveKeys\n\n\tviewStateStorageLock.Lock()\n\tdefer viewStateStorageLock.Unlock()\n\n\tstorage, err := getViewStateStorage()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstate := storage.Views[key]\n\tif nil == state {","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/view_state.go#L87-L123","documentation":"PatchViewState size guard in the kernel view-state storage: the marshalled patch payload exceeds maxViewStatePatchBytes (after already passing the entry-count check). The client sent a single state update too large to store atomically.","triggerScenarios":"Calling PatchViewState where the JSON-serialized viewStatePatch{Values, RemoveKeys} is larger than maxViewStatePatchBytes — typically a few large values (e.g. big nested arrays, base64 blobs) rather than many keys.","commonSituations":"Caching large documents or image data inside a single view-state value; storing base64-encoded assets in UI state; a plugin accumulating ever-growing state in one value that eventually crosses the byte cap.","solutions":["Reduce value size: strip or truncate large nested data before patching","Split the payload across multiple keys and patch them separately, if each resulting patch fits the byte cap","Move bulk data to a dedicated storage (kernel-side file or SQL) and keep only a reference/ID in view state"],"exampleFix":"// before\n_, err := model.PatchViewState(key, map[string]any{\"blob\": base64Content}, nil)\n// after\nid, _ := model.StoreAsset(boxID, content) // store bulk data elsewhere\n_, err := model.PatchViewState(key, map[string]any{\"blobRef\": id}, nil)","handlingStrategy":"try-catch","validationCode":"func isPatchBytesOK(values map[string]any, removeKeys []string) bool {\n    data, err := json.Marshal(map[string]any{\"Values\": values, \"RemoveKeys\": removeKeys})\n    return err == nil && len(data) <= model.MaxViewStatePatchBytes\n}","typeGuard":null,"tryCatchPattern":"_, err := model.PatchViewState(key, values, removeKeys)\nif err != nil && strings.Contains(err.Error(), \"patch is too large\") {\n    // shrink values (drop/truncate large ones) and retry once\n    for k, v := range values {\n        if jsonSize(v) > largeValueThreshold {\n            delete(values, k)\n        }\n    }\n    _, err = model.PatchViewState(key, values, removeKeys)\n}\nreturn err","preventionTips":["Measure the JSON size of large values before patching; view state is not a blob store","Keep bulk data (documents, images, base64) in dedicated storage and reference it by ID in view state","Bound the size of any single view-state value at write time so later patches stay under the cap"],"tags":["validation","view-state","limits","size","siyuan"],"backgroundTag":"payload-too-large","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}