{"record":{"id":"40fd4f92a4e7a7d9","repo":"siyuan-note/siyuan","slug":"view-state-storage-is-too-large","errorCode":null,"errorMessage":"view state storage is too large","messagePattern":"view state storage is too large","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/view_state.go","lineNumber":394,"sourceCode":"\t}\n\treturn\n}\n\nfunc marshalViewStateStorage(storage *viewStateStorage) (data []byte, err error) {\n\tfor {\n\t\tdata, err = gulu.JSON.MarshalIndentJSON(storage, \"\", \"  \")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(data) <= maxViewStateStorageSize {\n\t\t\treturn\n\t\t}\n\t\tif len(storage.Views) <= 1 {\n\t\t\tkey := oldestViewStateKey(storage.Views)\n\t\t\tstate := storage.Views[key]\n\t\t\tnormalizeViewStateFieldOrder(state)\n\t\t\tif 0 == len(state.Order) {\n\t\t\t\treturn nil, errors.New(\"view state storage is too large\")\n\t\t\t}\n\t\t\tdelete(state.Data, state.Order[0])\n\t\t\tstate.Order = state.Order[1:]\n\t\t\tif 0 == len(state.Data) {\n\t\t\t\tdelete(storage.Views, key)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tdelete(storage.Views, oldestViewStateKey(storage.Views))\n\t}\n}\n\nfunc oldestViewStateKey(views map[string]*ViewState) (ret string) {\n\tfor key, state := range views {\n\t\tif \"\" == ret || state.Updated < views[ret].Updated ||\n\t\t\t(state.Updated == views[ret].Updated && key < ret) {\n\t\t\tret = key\n\t\t}","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/view_state.go#L376-L412","documentation":"marshalViewStateStorage enforces a size budget when serializing view-state storage. It evicts oldest views and trims data entries; if even the last remaining view's single data entry cannot be dropped (its Order is empty, i.e. nothing left to shed) and the payload still exceeds the limit, it gives up with this error rather than persisting an over-large blob.","triggerScenarios":"setViewStateStorage / getViewStateStorage marshals storage whose JSON exceeds the size limit even after pruning: a single view holds one huge data value and no further entries can be removed.","commonSituations":"A plugin stored a very large object (e.g. a serialized document, big JSON blob, base64 image) as one view-state data entry, so trimming order entries cannot shrink the payload below the cap.","solutions":["Reduce the size of individual view-state data values: store large payloads externally and keep only a reference/ID in the view state.","Remove stale keys from the view's Data/Order so the trimmer has entries to evict.","Split large state across multiple smaller data keys instead of one oversized entry."],"exampleFix":"// before\nawait setViewState(viewId, \"snapshot\", hugeDocumentJSON);\n\n// after\nconst id = saveExternalBlob(hugeDocumentJSON);\nawait setViewState(viewId, \"snapshotRef\", { blobId: id });","handlingStrategy":"validation","validationCode":"function fitsViewStateBudget(obj, limit = 512 * 1024) {\n  return JSON.stringify(obj).length <= limit; // guard before writing\n}\nif (!fitsViewStateBudget({ [key]: value })) {\n  throw new Error(\"view state payload too large; store externally\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await setViewState(viewId, key, data);\n} catch (e) {\n  if (String(e).includes(\"view state storage is too large\")) {\n    await setViewState(viewId, key, await storeExternally(data)); // fallback to reference\n  } else { throw e; }\n}","preventionTips":["Never store documents, blobs, or base64 media in view state; store references instead.","Estimate serialized size before writing and split large state.","Periodically delete obsolete data keys from views."],"tags":["size-limit","persistence","storage-quota"],"backgroundTag":"file-size-limit-exceeded","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"}