siyuan-note/siyuan · error
options must not be empty; use optionRemove to delete…
Error message
options must not be empty; use optionRemove to delete existing options
What it means
When replacing the option list of a select/mselect field ('options' setting), the new list must contain at least one option. SiYuan deliberately forbids clearing all options through this path and directs you to the 'optionRemove' setting, which safely removes a single existing option and handles rows that reference it.
Solutions
- Send the full desired non-empty option list instead of an empty array
- Use setting "optionRemove" with the option's name to delete a single existing option
- If the field truly must have no options, delete the field and recreate it, or add at least one placeholder option
Example fix
// before
{avID, keyID, setting: "options", data: []}
// after
{avID, keyID, setting: "optionRemove", data: "Unused Option"} Defensive patterns
Strategy: validation
Validate before calling
if (setting === "options" && (!Array.isArray(options) || options.length === 0)) {
throw new Error("use optionRemove to delete an option, cannot send empty options list");
} Type guard
const canReplaceOptions = (opts) => Array.isArray(opts) && opts.length > 0;
Prevention
- Treat 'options' as full-list replacement only when at least one option remains
- Route single deletions through the optionRemove setting
When it happens
Trigger: Calling UpdateAttributeViewKeyConfig with setting "options" and an empty array (or null-length decode result) for a select/multi-select key.
Common situations: Frontend sends the current option list minus the one the user deleted, leaving zero items; bulk-import code writes an empty array for fields with no options yet; template that resets a field's options to [].
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- each option requires a nonempty name
- new option name must not be empty
- at least one visible view is required
- attribute view custom color index
- attribute view custom color must not be null
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/74c5ad703b17f3ba.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/attribute_view_key_config.go:200
return errors.New("configuration must not be null")
}
data, err := json.Marshal(value)
if nil != err {
return err
}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
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 {View on GitHub (pinned to 9f775e8a12)