siyuan-note/siyuan · error

attribute view custom color must not be null

Error message

attribute view custom color must not be null

What it means

normalizeAttributeViewCustomColor rejects a nil color entry with this sentinel message. A null element inside the custom colors array carries no index or theme data and cannot be normalized, so it is treated as invalid input.

Source

Thrown at kernel/av/color.go:129

			}
			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 {
		return nil, errors.New("attribute view custom color must not be null")
	}
	if color.Index < CustomColorMinIndex || CustomColorMaxIndex < color.Index {
		return nil, fmt.Errorf("attribute view custom color index [%d] is out of range [%d, %d]",
			color.Index, CustomColorMinIndex, CustomColorMaxIndex)
	}

	ret = &AttributeViewCustomColor{Index: color.Index, Hidden: color.Hidden}
	ret.Light, err = normalizeAttributeViewColorTheme(color.Light)
	if nil != err {
		return nil, fmt.Errorf("invalid light theme of attribute view custom color [%d]: %w", color.Index, err)
	}
	ret.Dark, err = normalizeAttributeViewColorTheme(color.Dark)
	if nil != err {
		return nil, fmt.Errorf("invalid dark theme of attribute view custom color [%d]: %w", color.Index, err)
	}
	return
}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Filter out nil entries before calling NormalizeAttributeViewCustomColors.
  2. Fix the JSON producer so absent colors are omitted from the array instead of written as null.
  3. If the null came from decoding into a fixed-size array, switch to a variadic slice or pre-size the slice correctly.
  4. In non-strict mode the entry still errors at normalizeAttributeViewCustomColor — filtering nils is required in both modes.

Example fix

// before
ret, err := av.NormalizeAttributeViewCustomColors(colors, true) // colors contains nil

// after
filtered := make([]*av.AttributeViewCustomColor, 0, len(colors))
for _, c := range colors {
	if c != nil {
		filtered = append(filtered, c)
	}
}
ret, err := av.NormalizeAttributeViewCustomColors(filtered, true)
Defensive patterns

Strategy: type-guard

Validate before calling

func nonNil(colors []*av.AttributeViewCustomColor) []*av.AttributeViewCustomColor {
	out := colors[:0]
	for _, c := range colors { if c != nil { out = append(out, c) } }
	return out
}

Type guard

func isValidColor(c *av.AttributeViewCustomColor) bool { return c != nil }

Try / catch

if _, err := av.NormalizeAttributeViewCustomColors(colors, true); err != nil && strings.Contains(err.Error(), "must not be null") {
	// filter nils and retry
}

Prevention

When it happens

Trigger: Passing a slice containing nil to av.NormalizeAttributeViewCustomColors (each element goes through normalizeAttributeViewCustomColor, color.go:129); JSON decoding that left null holes in the colors array (e.g. `[null, {...}]` or oversized arrays zero-filled).

Common situations: JSON like "customColors":[null,...] produced by another tool or a buggy writer; Go code building the slice with a nil entry from a failed lookup; a migration importing palettes where missing entries became null instead of being skipped.

Related errors


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