siyuan-note/siyuan · error

attribute view custom colors count exceeds the %d item limit

Error message

attribute view custom colors count exceeds the %d item limit

What it means

NormalizeAttributeViewCustomColors returns this error in strict mode when the caller supplies more custom colors than MaxCustomColors allows (CustomColorMaxIndex 78 - CustomColorMinIndex 15 + 1 = 64). The limit exists because each custom color occupies one reserved index slot in the color space.

Source

Thrown at kernel/av/color.go:96

// UnmarshalJSON 忽略外部输入中的派生颜色,派生颜色只能由内核根据数据库调色板生成。
func (value *ValueSelect) UnmarshalJSON(data []byte) error {
	decoded := struct {
		Content string `json:"content"`
		Color   string `json:"color"`
	}{}
	if err := json.Unmarshal(data, &decoded); nil != err {
		return err
	}
	value.Content = decoded.Content
	value.Color = decoded.Color
	value.ResolvedColor = nil
	return nil
}

// 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{}{}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Trim the color list to at most av.MaxCustomColors (64) entries before normalizing in strict mode.
  2. Pass strict=false if best-effort normalization (dedupe/trim silently) is acceptable — non-strict mode drops extras instead of erroring.
  3. Assign colors to the reserved index range [CustomColorMinIndex 15, CustomColorMaxIndex 78]; if the palette is larger, remap to built-in colors instead of custom slots.
  4. Merge duplicates first (same index/light/dark) to reduce the count before calling.

Example fix

// before
ret, err := av.NormalizeAttributeViewCustomColors(colors, true) // 80 colors -> error

// after
if len(colors) > av.MaxCustomColors {
	colors = colors[:av.MaxCustomColors]
}
ret, err := av.NormalizeAttributeViewCustomColors(colors, true)
Defensive patterns

Strategy: validation

Validate before calling

func withinColorLimit(colors []*av.AttributeViewCustomColor) bool {
	return len(colors) <= av.MaxCustomColors // 64
}

Try / catch

if _, err := av.NormalizeAttributeViewCustomColors(colors, true); err != nil && strings.Contains(err.Error(), "count exceeds") {
	colors = colors[:av.MaxCustomColors]
}

Prevention

When it happens

Trigger: Calling av.NormalizeAttributeViewCustomColors(colors, true) with len(colors) > 64; setAttrViewCustomColors or palette decoding paths (decodeHistoricalWorkspacePalette, customColorPalette) receiving an oversized palette.

Common situations: Importing/pasting a palette from another workspace or tool with more entries than the reserved index range; a migration script enumerating indexes without knowing the 15..78 bound; merging two color configurations.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/d58892a4d5909f85. Report an issue: GitHub.