{"record":{"id":"4bf0fe879a938782","repo":"siyuan-note/siyuan","slug":"duplicate-workspace-attribute-view-builtin-color-u","errorCode":null,"errorMessage":"duplicate workspace attribute view builtin color update [%d]","messagePattern":"duplicate workspace attribute view builtin color update \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/inline_style.go","lineNumber":198,"sourceCode":"\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)\n\t\t}\n\t\tupdatedIndexes[patch.Index] = struct{}{}\n\t\tfiltered := current.Builtin.Colors[:0]\n\t\tfor _, color := range current.Builtin.Colors {\n\t\t\tif color.Index != patch.Index {\n\t\t\t\tfiltered = append(filtered, color)\n\t\t\t}\n\t\t}\n\t\tcurrent.Builtin.Colors = filtered\n\t\tif patch.Customized {\n\t\t\tcurrent.Builtin.Colors = append(current.Builtin.Colors, &InlineStyleBuiltinColor{\n\t\t\t\tIndex: patch.Index,\n\t\t\t\tLight: patch.Light,\n\t\t\t\tDark:  patch.Dark,\n\t\t\t})\n\t\t}\n\t\tfilteredHidden := current.Builtin.Hidden.AV[:0]\n\t\tfor _, index := range current.Builtin.Hidden.AV {","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/inline_style.go#L180-L216","documentation":"SetWorkspaceAVPalette tracks already-seen builtin color indexes in updatedIndexes while iterating update.BuiltinColors. If two patches target the same index the update is ambiguous, so it fails with this error instead of applying the patches in undocumented order.","triggerScenarios":"Passing a WorkspaceAVPaletteUpdate whose BuiltinColors slice contains two or more patches with the same Index value — the second occurrence triggers the duplicate check in the loop.","commonSituations":"Frontend accumulates color edits without deduplicating by index before saving; a plugin merges multiple patch sets naively with append; retry logic appends a patch twice.","solutions":["Deduplicate BuiltinColors by Index (last-wins or first-wins per your intent) before calling SetWorkspaceAVPalette","Build the patch list as a map[int]*InlineStyleBuiltinColorPatch during collection, then convert to a slice","Fix the caller's merge/retry logic so the same index is never appended twice"],"exampleFix":"// before: duplicate indexes appended\npatches = append(patches, &model.InlineStyleBuiltinColorPatch{Index: 3, Color: red})\npatches = append(patches, &model.InlineStyleBuiltinColorPatch{Index: 3, Color: blue}) // duplicate\n// after: dedupe by index, last wins\nbyIndex := map[int]*model.InlineStyleBuiltinColorPatch{}\nbyIndex[3] = &model.InlineStyleBuiltinColorPatch{Index: 3, Color: red}\nbyIndex[3] = &model.InlineStyleBuiltinColorPatch{Index: 3, Color: blue}\nfor _, p := range byIndex { patches = append(patches, p) }","handlingStrategy":"validation","validationCode":"seen := map[int]bool{}\nfor _, p := range patches {\n\tif seen[p.Index] { return fmt.Errorf(\"duplicate patch index %d\", p.Index) }\n\tseen[p.Index] = true\n}","typeGuard":null,"tryCatchPattern":"_, _, err := model.SetWorkspaceAVPalette(update)\nif err != nil && strings.Contains(err.Error(), \"duplicate workspace attribute view builtin color\") {\n\t// deduplicate by index and retry\n}","preventionTips":["Collect patches in a map[int]Patch and convert to a slice at the end","Deduplicate accumulated edits before saving the palette","Make retry/merge logic idempotent per index"],"tags":["attribute-view","palette","duplicate","builtin-colors"],"backgroundTag":"conflicting-config-options","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}