siyuan-note/siyuan · error
view state patch is too large
Error message
view state patch is too large
What it means
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.
Source
Thrown at kernel/model/view_state.go:105
return nil, errors.New("view state patch contains too many entries")
}
for valueKey := range values {
if err = validateViewStateDataKey(valueKey); err != nil {
return nil, err
}
}
for _, removeKey := range removeKeys {
if err = validateViewStateDataKey(removeKey); err != nil {
return nil, err
}
}
patch := &viewStatePatch{Values: values, RemoveKeys: removeKeys}
patchData, marshalErr := gulu.JSON.MarshalJSON(patch)
if nil != marshalErr {
return nil, marshalErr
}
if maxViewStatePatchBytes < len(patchData) {
return nil, errors.New("view state patch is too large")
}
// 后续合并使用序列化快照,避免调用方在请求执行期间继续修改嵌套值。
normalizedPatch := &viewStatePatch{}
if err = gulu.JSON.UnmarshalJSON(patchData, &normalizedPatch); nil != err {
return nil, err
}
values = normalizedPatch.Values
removeKeys = normalizedPatch.RemoveKeys
viewStateStorageLock.Lock()
defer viewStateStorageLock.Unlock()
storage, err := getViewStateStorage()
if err != nil {
return nil, err
}
state := storage.Views[key]
if nil == state {View on GitHub (pinned to 8641553a1f)
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
Example fix
// before
_, err := model.PatchViewState(key, map[string]any{"blob": base64Content}, nil)
// after
id, _ := model.StoreAsset(boxID, content) // store bulk data elsewhere
_, err := model.PatchViewState(key, map[string]any{"blobRef": id}, nil) Defensive patterns
Strategy: try-catch
Validate before calling
func isPatchBytesOK(values map[string]any, removeKeys []string) bool {
data, err := json.Marshal(map[string]any{"Values": values, "RemoveKeys": removeKeys})
return err == nil && len(data) <= model.MaxViewStatePatchBytes
} Try / catch
_, err := model.PatchViewState(key, values, removeKeys)
if err != nil && strings.Contains(err.Error(), "patch is too large") {
// shrink values (drop/truncate large ones) and retry once
for k, v := range values {
if jsonSize(v) > largeValueThreshold {
delete(values, k)
}
}
_, err = model.PatchViewState(key, values, removeKeys)
}
return err Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- view state patch contains too many entries
- Maximum length is limited to 512 characters
- invalid view state key
- wrong layout type
- filter nesting depth exceeds the maximum allowed
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/a978268805c48e30.
Report an issue: GitHub.