{"record":{"id":"b059c87ce997faaf","repo":"siyuan-note/siyuan","slug":"view-state-value-is-too-large","errorCode":null,"errorMessage":"View state value is too large","messagePattern":"View state value is too large","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/util/viewState.ts","lineNumber":239,"sourceCode":"                const nextRemoveKeys = [...removeKeys, field];\n                if (count > 0 && (count >= MAX_PATCH_ENTRIES ||\n                    getPatchByteLength(values, nextRemoveKeys) > MAX_PATCH_BYTES)) {\n                    break;\n                }\n                removeKeys.push(field);\n                this.pendingRemovals.delete(field);\n                count++;\n            }\n        }\n        if (count === 0) {\n            throw new Error(\"View state patch cannot be split within the storage limits\");\n        }\n        return {values, removeKeys};\n    }\n\n    private validateValue(field: string, value: TViewStateValue) {\n        if (getPatchByteLength({[field]: value}, []) > MAX_PATCH_BYTES) {\n            throw new Error(\"View state value is too large\");\n        }\n    }\n\n    private scheduleFlush() {\n        this.clearFlushTimer();\n        this.flushTimer = setTimeout(() => {\n            this.flushTimer = undefined;\n            this.flush().catch((error) => console.error(error));\n        }, this.flushDelay);\n    }\n\n    private clearFlushTimer() {\n        if (this.flushTimer !== undefined) {\n            clearTimeout(this.flushTimer);\n            this.flushTimer = undefined;\n        }\n    }\n","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/app/src/util/viewState.ts#L221-L257","documentation":"ViewStateService.validateValue throws this when a single field value serialized to JSON (wrapped in the {values:{field:value},removeKeys:[]} patch envelope) exceeds MAX_PATCH_BYTES (256 KiB). Each individual set()/patch() value must be small enough that the server patch request can always carry it. It is a client-side guard against writes that could never be flushed to kernel storage.","triggerScenarios":"Calling viewStateService.set(field, value) or patch({...}) where JSON.stringify of that one field's value (including the patch envelope overhead) is larger than 256*1024 bytes. Examples: storing a whole Protyle scroll/render snapshot, base64 images, or a large JSON blob in one field.","commonSituations":"Developers treat view state as a free-form key-value store and stash large documents, serialized editor content, or cached data in it; a field grows over time (e.g. accumulating entries in an array) until it crosses the 256 KiB limit.","solutions":["Reduce the size of the stored value: keep only the minimal UI state (scroll offsets, collapsed flags, IDs), not full content","Split the data across multiple fields, or store the large payload elsewhere (kernel file/asset or a dedicated storage API) and keep only a reference key in view state","Prune the value before writing (e.g. cap array length, truncate strings, strip redundant properties)","If the data legitimately must persist, use a different persistence mechanism such as plugin storage or a custom kernel endpoint instead of view state"],"exampleFix":"// before\nservice.set(\"layout\", entireProtyleSnapshot); // hundreds of KB\n// after\nservice.set(\"layout\", { scroll: snapshot.scroll, zoom: snapshot.zoom }); // keep only small fields","handlingStrategy":"validation","validationCode":"const MAX_PATCH_BYTES = 256 * 1024;\nconst getPatchByteLength = (values, removeKeys) =>\n    new TextEncoder().encode(JSON.stringify({values, removeKeys})).byteLength;\nif (getPatchByteLength({[field]: value}, []) > MAX_PATCH_BYTES) {\n    throw new Error(`view state value for \"${field}\" exceeds 256 KiB; split or shrink it`);\n}\nservice.set(field, value);","typeGuard":"const isSmallEnough = (field: string, value: unknown): boolean => {\n    try {\n        return new TextEncoder().encode(\n            JSON.stringify({values: {[field]: value}, removeKeys: []})\n        ).byteLength <= 256 * 1024;\n    } catch {\n        return false; // not JSON-serializable\n    }\n};","tryCatchPattern":null,"preventionTips":["Store only minimal UI state (offsets, flags, IDs) in view state, never full content","Check serialized size of large fields before writing; cap arrays and truncate strings","Keep big payloads in files/assets or a dedicated storage API and reference them by key","Remember the envelope adds overhead — measure with the same getPatchByteLength logic, not raw JSON length"],"tags":["view-state","payload-too-large","storage","frontend"],"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-14T00:17:10.932Z"}