siyuan-note/siyuan · error

invalid option color

Error message

invalid option color

What it means

Option colors must match one of SiYuan's canonical filter/option colors. attrView.FilterColorValue normalizes a submitted color, and if normalization changes it the value was not one of the accepted palette strings, so the update is rejected.

Solutions

  1. Use one of the accepted option/filter color values (the palette shown in the SiYuan field editor)
  2. Drop the color field so the default/normalized color is applied
  3. Normalize via the same FilterColorValue logic client-side before sending

Example fix

// before
{"name":"Todo","color":"#e54545"}
// after
{"name":"Todo","color":"4"}
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED_COLORS = new Set(["","1","2","3","4","5","6","7","8","9","10","11","12","13"]);
if (!ALLOWED_COLORS.has(option.color)) throw new Error(`unsupported option color: ${option.color}`);

Prevention

When it happens

Trigger: Updating options ('options' setting) or renaming an option ('optionUpdate' with color) where Color is an arbitrary hex string like "#ff0000", an out-of-range index, or a non-canonical value.

Common situations: Plugin code picking its own palette colors; importer mapping another app's tag colors 1:1; frontend sending a CSS color instead of SiYuan's filter-color value.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/4f96aae2671c3d03. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view_key_config.go:211

func updateAttributeViewKeyOptions(attrView *av.AttributeView, key *av.Key, op *Operation, setting string, value any) error {
	if "options" == setting {
		var options []*av.SelectOption
		if err := decodeAttributeViewKeyConfig(value, &options); nil != err {
			return err
		}
		if 0 == len(options) {
			return errors.New("options must not be empty; use optionRemove to delete existing options")
		}
		names := map[string]bool{}
		for _, option := range options {
			if nil == option || "" == strings.TrimSpace(option.Name) {
				return errors.New("each option requires a nonempty name")
			}
			if names[option.Name] {
				return errors.New("duplicate option name")
			}
			if attrView.FilterColorValue(option.Color) != option.Color {
				return errors.New("invalid option color")
			}
			names[option.Name] = true
		}
		op.Data = options
		return updateAttributeViewColumnOptions(op)
	}
	if "optionRemove" == setting {
		name, ok := value.(string)
		if !ok || nil == key.GetOption(name) {
			return errors.New("optionRemove must name an existing option")
		}
		op.Data = name
		return removeAttributeViewColumnOption(op)
	}
	var config struct {
		Name    string  `json:"name"`
		NewName *string `json:"newName"`
		Color   *string `json:"color"`

View on GitHub (pinned to 9f775e8a12)