{"record":{"id":"58df254ec0ed303d","repo":"siyuan-note/siyuan","slug":"view-state-patch-contains-too-many-entries","errorCode":null,"errorMessage":"view state patch contains too many entries","messagePattern":"view state patch contains too many entries","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/view_state.go","lineNumber":87,"sourceCode":"\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 || nil == state.Data {\n\t\treturn map[string]any{}, nil\n\t}\n\treturn cloneViewStateData(state.Data)\n}\n\nfunc PatchViewState(key string, values map[string]any, removeKeys []string) (ret map[string]any, err error) {\n\tif err = validateViewStateKey(key); err != nil {\n\t\treturn\n\t}\n\tif maxViewStatePatchCount < len(values)+len(removeKeys) {\n\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\")","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/view_state.go#L69-L105","documentation":"PatchViewState limits the total number of entries in a single patch (values plus removeKeys) to maxViewStatePatchCount. Patches exceeding that cap are rejected before validation and merge, keeping view-state storage bounded and patches small.","triggerScenarios":"Calling PatchViewState with len(values)+len(removeKeys) greater than maxViewStatePatchCount, e.g. one call that sets or removes hundreds of data keys at once for the same view-state key.","commonSituations":"Persisting a large bulk state blob (many keys) in one patch instead of a few aggregated values; a plugin syncing many UI flags in one call; batch cleanup that removes a long list of keys in a single removeKeys slice.","solutions":["Split the patch into multiple sequential PatchViewState calls, each under the entry-count cap","Aggregate many flags into a single JSON value under one data key instead of one key per flag","Trim the patch: remove only stale keys and set only changed values"],"exampleFix":"// before\nret, err := model.PatchViewState(key, allValues, allRemoveKeys) // hundreds of entries\n// after\nconst batchSize = 50\nfor i := 0; i < len(allValues); i += batchSize {\n    if _, err = model.PatchViewState(key, subMap(allValues, i, batchSize), nil); err != nil {\n        break\n    }\n}","handlingStrategy":"try-catch","validationCode":"func isPatchSizeOK(values map[string]any, removeKeys []string) bool {\n    return len(values)+len(removeKeys) <= model.MaxViewStatePatchCount\n}","typeGuard":null,"tryCatchPattern":"_, err := model.PatchViewState(key, values, removeKeys)\nif err != nil && strings.Contains(err.Error(), \"too many entries\") {\n    // split into smaller batches and retry\n    for batch := range chunkMap(values, 50) {\n        if _, err = model.PatchViewState(key, batch, nil); err != nil {\n            return err\n        }\n    }\n    return model.PatchViewState(key, nil, removeKeys)\n}\nreturn err","preventionTips":["Keep the number of view-state keys per view small; aggregate related flags into one object value","Batch large patches into chunks safely below the entry cap","Only include keys that actually changed instead of re-sending full state each time"],"tags":["validation","view-state","limits","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-14T00:17:10.932Z"}