siyuan-note/siyuan · error
workspace attribute view palette update must not be null
Error message
workspace attribute view palette update must not be null
What it means
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).
Source
Thrown at kernel/model/inline_style.go:180
waitForSyncingStorages()
inlineStylesLock.Lock()
defer inlineStylesLock.Unlock()
current, err := loadInlineStyles()
if err != nil {
return nil, false, err
}
return setInlineStylesData(styles, current.AV)
}
// SetWorkspaceAVPalette 只更新数据库颜色配置,保留其他窗口可能同时修改的行级样式设置。
func SetWorkspaceAVPalette(update *WorkspaceAVPaletteUpdate) (ret *InlineStyles, changed bool, err error) {
waitForSyncingStorages()
inlineStylesLock.Lock()
defer inlineStylesLock.Unlock()
if update == nil {
return nil, false, errors.New("workspace attribute view palette update must not be null")
}
current, err := loadInlineStyles()
if err != nil {
return nil, false, err
}
currentAV := current.AV
current.AV = &InlineStyleAV{Colors: update.Colors, Order: update.Order}
updatedIndexes := map[int]struct{}{}
for _, patch := range update.BuiltinColors {
if patch == nil {
return nil, false, errors.New("workspace attribute view builtin color update must not be null")
}
if patch.Index < minBuiltinColorIndex || neutralAVColorIndex < patch.Index {
return nil, false, fmt.Errorf("builtin color index [%d] must be between %d and %d", patch.Index,
minBuiltinColorIndex, neutralAVColorIndex)
}
if _, duplicated := updatedIndexes[patch.Index]; duplicated {
return nil, false, fmt.Errorf("duplicate workspace attribute view builtin color update [%d]", patch.Index)View on GitHub (pinned to 8641553a1f)
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
Example fix
// before: nil update passed straight through
var update *model.WorkspaceAVPaletteUpdate
model.SetWorkspaceAVPalette(update) // error
// after
update := &model.WorkspaceAVPaletteUpdate{Colors: colors, Order: order}
if update == nil {
return nil, errors.New("palette update required")
}
model.SetWorkspaceAVPalette(update) Defensive patterns
Strategy: type-guard
Validate before calling
if update == nil {
return errors.New("palette update required")
} Type guard
func hasPaletteUpdate(u *model.WorkspaceAVPaletteUpdate) bool { return u != nil } Try / catch
ret, changed, err := model.SetWorkspaceAVPalette(update)
if err != nil && strings.Contains(err.Error(), "must not be null") {
// request body was empty; return 400 to the client
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- workspace attribute view builtin color update must not be nu
- [%s] parameter [%s] is deprecated, visit [https://github.com
- attribute view custom color [%d] is still in use
- parent ID is required
- previous ID and next ID cannot both be specified
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/972b0c36664a4628.
Report an issue: GitHub.