{"record":{"id":"972b0c36664a4628","repo":"siyuan-note/siyuan","slug":"workspace-attribute-view-palette-update-must-not-b","errorCode":null,"errorMessage":"workspace attribute view palette update must not be null","messagePattern":"workspace attribute view palette update must not be null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/inline_style.go","lineNumber":180,"sourceCode":"\twaitForSyncingStorages()\n\tinlineStylesLock.Lock()\n\tdefer inlineStylesLock.Unlock()\n\n\tcurrent, err := loadInlineStyles()\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\treturn setInlineStylesData(styles, current.AV)\n}\n\n// SetWorkspaceAVPalette 只更新数据库颜色配置，保留其他窗口可能同时修改的行级样式设置。\nfunc SetWorkspaceAVPalette(update *WorkspaceAVPaletteUpdate) (ret *InlineStyles, changed bool, err error) {\n\twaitForSyncingStorages()\n\tinlineStylesLock.Lock()\n\tdefer inlineStylesLock.Unlock()\n\n\tif update == nil {\n\t\treturn nil, false, errors.New(\"workspace attribute view palette update must not be null\")\n\t}\n\tcurrent, err := loadInlineStyles()\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tcurrentAV := current.AV\n\tcurrent.AV = &InlineStyleAV{Colors: update.Colors, Order: update.Order}\n\tupdatedIndexes := map[int]struct{}{}\n\tfor _, patch := range update.BuiltinColors {\n\t\tif patch == nil {\n\t\t\treturn nil, false, errors.New(\"workspace attribute view builtin color update must not be null\")\n\t\t}\n\t\tif patch.Index < minBuiltinColorIndex || neutralAVColorIndex < patch.Index {\n\t\t\treturn nil, false, fmt.Errorf(\"builtin color index [%d] must be between %d and %d\", patch.Index,\n\t\t\t\tminBuiltinColorIndex, neutralAVColorIndex)\n\t\t}\n\t\tif _, duplicated := updatedIndexes[patch.Index]; duplicated {\n\t\t\treturn nil, false, fmt.Errorf(\"duplicate workspace attribute view builtin color update [%d]\", patch.Index)","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/inline_style.go#L162-L198","documentation":"SetWorkspaceAVPalette is the kernel API for replacing the workspace attribute-view color palette stored in inline styles. It requires a non-nil *WorkspaceAVPaletteUpdate; a nil update would clear the palette unintentionally, so it returns this error immediately (after waiting for syncing storages and acquiring the lock).","triggerScenarios":"Calling model.SetWorkspaceAVPalette(nil), e.g. from the api handler setWorkspaceAVPalette when the request payload failed to decode into a non-nil update object, or from a test passing nil.","commonSituations":"Frontend sends an empty/missing JSON body so Gin binds a nil pointer; plugin constructs the update struct incorrectly and passes nil; refactoring renamed the field so decoding yields nil.","solutions":["Ensure the API request body contains a valid WorkspaceAVPaletteUpdate object before calling the kernel","In the frontend handler, reject/validate empty payloads with a 400 before invoking SetWorkspaceAVPalette","In Go callers/tests, construct the update struct (e.g. &WorkspaceAVPaletteUpdate{Colors: ..., Order: ...}) instead of passing nil"],"exampleFix":"// before: nil update passed straight through\nvar update *model.WorkspaceAVPaletteUpdate\nmodel.SetWorkspaceAVPalette(update) // error\n// after\nupdate := &model.WorkspaceAVPaletteUpdate{Colors: colors, Order: order}\nif update == nil {\n\treturn nil, errors.New(\"palette update required\")\n}\nmodel.SetWorkspaceAVPalette(update)","handlingStrategy":"type-guard","validationCode":"if update == nil {\n\treturn errors.New(\"palette update required\")\n}","typeGuard":"func hasPaletteUpdate(u *model.WorkspaceAVPaletteUpdate) bool { return u != nil }","tryCatchPattern":"ret, changed, err := model.SetWorkspaceAVPalette(update)\nif err != nil && strings.Contains(err.Error(), \"must not be null\") {\n\t// request body was empty; return 400 to the client\n}","preventionTips":["Always construct the update struct before calling the kernel","Validate non-empty JSON bodies in the API handler before binding","Never pass nil struct pointers from tests or plugins"],"tags":["attribute-view","palette","nil-argument","api"],"backgroundTag":"null-argument","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"}