siyuan-note/siyuan · error

duplicate builtin color index [%d]

Error message

duplicate builtin color index [%d]

What it means

Two builtin color entries declare the same `index`. Builtin color indexes are unique identifiers for the 14 palette slots, so normalizeInlineStyleBuiltin rejects duplicates to keep palette order, hiding configuration (builtin.Hidden.Color/AV), and AV color rendering unambiguous.

Source

Thrown at kernel/model/inline_style.go:720

}

func normalizeInlineStyleBuiltin(builtin *InlineStyleBuiltin) (ret *InlineStyleBuiltin, err error) {
	ret = newEmptyInlineStyleBuiltin()
	if builtin == nil {
		return ret, nil
	}

	colorIndexes := make(map[int]struct{}, len(builtin.Colors))
	for _, color := range builtin.Colors {
		if color == nil {
			return nil, errors.New("builtin color must not be null")
		}
		if color.Index < minBuiltinColorIndex || neutralAVColorIndex < color.Index {
			return nil, fmt.Errorf("builtin color index [%d] must be between %d and %d", color.Index,
				minBuiltinColorIndex, neutralAVColorIndex)
		}
		if _, exists := colorIndexes[color.Index]; exists {
			return nil, fmt.Errorf("duplicate builtin color index [%d]", color.Index)
		}
		colorIndexes[color.Index] = struct{}{}

		light, dark, err := normalizeInlineStyleThemePair(color.Light, color.Dark, fmt.Sprintf("builtin color [%d]", color.Index))
		if err != nil {
			return nil, err
		}
		ret.Colors = append(ret.Colors, &InlineStyleBuiltinColor{Index: color.Index, Light: light, Dark: dark})
	}
	sort.Slice(ret.Colors, func(i, j int) bool {
		return ret.Colors[i].Index < ret.Colors[j].Index
	})

	styleIDs := make(map[string]struct{}, len(builtin.Styles))
	for _, style := range builtin.Styles {
		if style == nil {
			return nil, errors.New("builtin style must not be null")
		}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Find the duplicated index in builtin.colors of inline-styles.json and renumber one entry to an unused index between 1 and 14.
  2. If both entries are unintended duplicates of the same palette slot, delete the redundant entry.
  3. Validate the array programmatically (collect indexes into a set) before saving the config or sending it via setInlineStylesData.

Example fix

// before
[{"index": 3, ...}, {"index": 3, ...}]
// after
[{"index": 3, ...}, {"index": 4, ...}]
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set();
for (const c of config.builtin.colors) {
  if (seen.has(c.index)) throw new Error(`duplicate builtin color index ${c.index}`);
  seen.add(c.index);
}

Prevention

When it happens

Trigger: setInlineStylesData or loadInlineStyles with builtin.colors containing two entries with the same index value, e.g. two entries both with `"index": 5`.

Common situations: Copy-pasting a color entry and forgetting to change its index; merging configuration files from two workspaces; a script cloning the last array element to add a new color.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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