siyuan-note/siyuan · error

duplicate option name

Error message

duplicate option name

What it means

The 'options' setting replaces the whole option list, and option names must be unique within a select/mselect field because they are the cell value identity. A submitted list containing the same name twice is rejected.

Solutions

  1. Deduplicate the option array by Name before sending
  2. Send one entry per option; update metadata of an existing option via "optionUpdate" instead of adding a second entry
  3. Normalize names (trim) before the uniqueness check client-side

Example fix

// before
[{"name":"Todo"},{"name":"Todo","color":"2"}]
// after
[{"name":"Todo","color":"2"}]
Defensive patterns

Strategy: validation

Validate before calling

const names = options.map(o => o.name);
if (new Set(names).size !== names.length) throw new Error("duplicate option names in payload");

Prevention

When it happens

Trigger: Calling UpdateAttributeViewKeyConfig with setting "options" where two entries share the same Name string (exact match, after no normalization other than the non-empty check).

Common situations: Merging option lists from two sources without deduplication; duplicating an entry when editing the payload by hand; case-variant duplicates like "todo" and "Todo" are distinct here but visually confusing, while exact duplicates fail.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/attribute_view_key_config.go:208

	return decoder.Decode(dest)
}

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 {

View on GitHub (pinned to 9f775e8a12)