siyuan-note/siyuan · error
view state storage is too large
Error message
view state storage is too large
What it means
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.
Source
Thrown at kernel/model/view_state.go:394
}
return
}
func marshalViewStateStorage(storage *viewStateStorage) (data []byte, err error) {
for {
data, err = gulu.JSON.MarshalIndentJSON(storage, "", " ")
if err != nil {
return nil, err
}
if len(data) <= maxViewStateStorageSize {
return
}
if len(storage.Views) <= 1 {
key := oldestViewStateKey(storage.Views)
state := storage.Views[key]
normalizeViewStateFieldOrder(state)
if 0 == len(state.Order) {
return nil, errors.New("view state storage is too large")
}
delete(state.Data, state.Order[0])
state.Order = state.Order[1:]
if 0 == len(state.Data) {
delete(storage.Views, key)
}
continue
}
delete(storage.Views, oldestViewStateKey(storage.Views))
}
}
func oldestViewStateKey(views map[string]*ViewState) (ret string) {
for key, state := range views {
if "" == ret || state.Updated < views[ret].Updated ||
(state.Updated == views[ret].Updated && key < ret) {
ret = key
}View on GitHub (pinned to 8641553a1f)
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.
Example fix
// before
await setViewState(viewId, "snapshot", hugeDocumentJSON);
// after
const id = saveExternalBlob(hugeDocumentJSON);
await setViewState(viewId, "snapshotRef", { blobId: id }); Defensive patterns
Strategy: validation
Validate before calling
function fitsViewStateBudget(obj, limit = 512 * 1024) {
return JSON.stringify(obj).length <= limit; // guard before writing
}
if (!fitsViewStateBudget({ [key]: value })) {
throw new Error("view state payload too large; store externally");
} Try / catch
try {
await setViewState(viewId, key, data);
} catch (e) {
if (String(e).includes("view state storage is too large")) {
await setViewState(viewId, key, await storeExternally(data)); // fallback to reference
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- Agent capability name and description are required
- Failed to save agent session
- BASE64_IMAGE_SIZE_LIMIT
- agent context cannot be compacted enough: persist compaction
- decode existing session data failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/40fd4f92a4e7a7d9.
Report an issue: GitHub.