siyuan-note/siyuan · error
duplicated attribute view custom color index [%d]
Error message
duplicated attribute view custom color index [%d]
What it means
NormalizeAttributeViewCustomColors returns this error in strict mode when two custom colors share the same Index. Each custom color index is a unique slot; duplicates are ambiguous for rendering, so strict mode rejects them while non-strict mode silently drops later duplicates.
Source
Thrown at kernel/av/color.go:110
// NormalizeAttributeViewCustomColors 校验并规范化数据库自定义颜色。
func NormalizeAttributeViewCustomColors(colors []*AttributeViewCustomColor, strict bool) (ret []*AttributeViewCustomColor, err error) {
if strict && MaxCustomColors < len(colors) {
return nil, fmt.Errorf("attribute view custom colors count exceeds the %d item limit", MaxCustomColors)
}
indexes := map[int]struct{}{}
for _, color := range colors {
normalized, normalizeErr := normalizeAttributeViewCustomColor(color)
if nil != normalizeErr {
if strict {
return nil, normalizeErr
}
continue
}
if _, ok := indexes[normalized.Index]; ok {
if strict {
return nil, fmt.Errorf("duplicated attribute view custom color index [%d]", normalized.Index)
}
continue
}
indexes[normalized.Index] = struct{}{}
ret = append(ret, normalized)
}
sort.Slice(ret, func(i, j int) bool {
return ret[i].Index < ret[j].Index
})
if nil == ret {
ret = []*AttributeViewCustomColor{}
}
return
}
func normalizeAttributeViewCustomColor(color *AttributeViewCustomColor) (ret *AttributeViewCustomColor, err error) {
if nil == color {View on GitHub (pinned to 8641553a1f)
Solutions
- Reassign duplicate entries with av.NextCustomColorIndex (or the next free index from UsedCustomColorIndexes) before normalizing.
- Dedupe by index first: keep one entry per index (merge Hidden/Light/Dark) and drop or merge the rest.
- Call NormalizeAttributeViewCustomColors with strict=false to silently drop duplicates if lossy handling is acceptable.
- When generating colors programmatically, always allocate via NextCustomColorIndex instead of hardcoded indexes.
Example fix
// before
colors := []*av.AttributeViewCustomColor{{Index: 15, ...}, {Index: 15, ...}} // duplicate
ret, err := av.NormalizeAttributeViewCustomColors(colors, true)
// after
colors[1].Index = av.NextCustomColorIndex(attrView)
ret, err := av.NormalizeAttributeViewCustomColors(colors, true) Defensive patterns
Strategy: validation
Validate before calling
func hasDuplicateIndexes(colors []*av.AttributeViewCustomColor) bool {
seen := map[int]struct{}{}
for _, c := range colors {
if _, ok := seen[c.Index]; ok { return true }
seen[c.Index] = struct{}{}
}
return false
} Try / catch
if _, err := av.NormalizeAttributeViewCustomColors(colors, true); err != nil && strings.Contains(err.Error(), "duplicated") {
// reassign with av.NextCustomColorIndex and retry
} Prevention
- Always allocate color indexes via av.NextCustomColorIndex
- Reindex entries when merging two views' palettes
- Use strict=false if silently dropping duplicates is acceptable
When it happens
Trigger: Calling av.NormalizeAttributeViewCustomColors(colors, true) where two entries carry the same Index (color.go:108); decoding a palette (decodeHistoricalWorkspacePalette) or applying colors via setAttrViewCustomColors with duplicated indexes.
Common situations: Merging two attribute views' color definitions without reindexing; a script appending new colors reusing an existing index instead of av.NextCustomColorIndex; hand-edited .av JSON with copy-pasted color blocks.
Related errors
- attribute view custom colors count exceeds the %d item limit
- attribute view custom color must not be null
- attribute view custom color index [%d] is out of range [%d,
- invalid light theme of attribute view custom color [%d]: %w
- ErrFilterTooDeep
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/7b0fcf59e906bbea.
Report an issue: GitHub.