{"record":{"id":"84a1a0b65752fdbe","repo":"siyuan-note/siyuan","slug":"local-storage-value-for-key-s-must-not-be-empty","errorCode":null,"errorMessage":"local storage value for key [%s] must not be empty","messagePattern":"local storage value for key \\[(.+?)\\] must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/storage.go","lineNumber":61,"sourceCode":"\tdefer localStorageLock.Unlock()\n\treturn getLocalStorage()\n}\n\nfunc SetLocalStorage(val map[string]any) (err error) {\n\tlocalStorageLock.Lock()\n\tdefer localStorageLock.Unlock()\n\treturn setLocalStorage(val)\n}\n\nfunc SetLocalStorageVals(keyVals map[string]any) (setKeyVals map[string]any, err error) {\n\tlocalStorageLock.Lock()\n\tdefer localStorageLock.Unlock()\n\n\tsetKeyVals = make(map[string]any, len(keyVals))\n\tlocalStorage := getLocalStorage()\n\tfor k, v := range keyVals {\n\t\tif v == nil {\n\t\t\terr = fmt.Errorf(\"local storage value for key [%s] must not be empty\", k)\n\t\t\treturn\n\t\t}\n\t\tlocalStorage[k] = v\n\t\tsetKeyVals[k] = v\n\t}\n\terr = setLocalStorage(localStorage)\n\treturn\n}\n\nfunc RemoveLocalStorageVals(keys []string) (err error) {\n\tlocalStorageLock.Lock()\n\tdefer localStorageLock.Unlock()\n\n\tlocalStorage := getLocalStorage()\n\tfor _, key := range keys {\n\t\tdelete(localStorage, key)\n\t}\n\treturn setLocalStorage(localStorage)","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/storage.go#L43-L79","documentation":"SetLocalStorageVals validates every key/value pair before persisting to the kernel's local storage (localStorage.json in the workspace). If any value in the submitted map is nil, the whole operation aborts with this error and nothing is written, since a nil value would corrupt the stored JSON map semantics. It is a client-input validation guard on the /api/storage/setLocalStorageVals endpoint.","triggerScenarios":"Calling kernel API /api/storage/setLocalStorageVals with a JSON payload where some key maps to null; frontend/plugin code doing localStorage setItem with an undefined-valued variable.","commonSituations":"A frontend reads an unset variable (undefined) and serializes it to null; a plugin builds the keyVals map programmatically and one optional field is missing; deserialized data lost a value.","solutions":["Inspect the keyVals payload and remove or replace every null value with a concrete value before calling the API","On the caller side, filter entries: build the map only from keys whose value is non-nil/non-undefined","If the key should be cleared, use the remove-local-storage API/omit the key instead of passing nil"],"exampleFix":"// before\nfetchPost(\"/api/storage/setLocalStorageVals\", {keyVals: {theme: undefinedVal}})\n// after\nif (undefinedVal != null) {\n  fetchPost(\"/api/storage/setLocalStorageVals\", {keyVals: {theme: undefinedVal}})\n}","handlingStrategy":"validation","validationCode":"function canSetLocalStorageVals(keyVals) {\n  return Object.entries(keyVals).every(([k, v]) => v != null);\n}\nif (!canSetLocalStorageVals(keyVals)) throw new Error(\"null value in keyVals\");","typeGuard":"function hasNoNilValues(m map[string]any) bool {\n  for _, v := range m { if v == nil { return false } }\n  return true\n}","tryCatchPattern":null,"preventionTips":["Filter out null/undefined entries before sending keyVals to the API","Use remove-key APIs instead of null to clear a stored value","In TypeScript, type payload values as NonNullable<T> to catch nulls at compile time"],"tags":["go","local-storage","validation","null-value"],"backgroundTag":"empty-required-field","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}