{"record":{"id":"abcd909b8993a1a8","repo":"siyuan-note/siyuan","slug":"each-option-requires-a-nonempty-name","errorCode":null,"errorMessage":"each option requires a nonempty name","messagePattern":"each option requires a nonempty name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_key_config.go","lineNumber":205,"sourceCode":"\t}\n\tdecoder := json.NewDecoder(bytes.NewReader(data))\n\tdecoder.DisallowUnknownFields()\n\treturn decoder.Decode(dest)\n}\n\nfunc updateAttributeViewKeyOptions(attrView *av.AttributeView, key *av.Key, op *Operation, setting string, value any) error {\n\tif \"options\" == setting {\n\t\tvar options []*av.SelectOption\n\t\tif err := decodeAttributeViewKeyConfig(value, &options); nil != err {\n\t\t\treturn err\n\t\t}\n\t\tif 0 == len(options) {\n\t\t\treturn errors.New(\"options must not be empty; use optionRemove to delete existing options\")\n\t\t}\n\t\tnames := map[string]bool{}\n\t\tfor _, option := range options {\n\t\t\tif nil == option || \"\" == strings.TrimSpace(option.Name) {\n\t\t\t\treturn errors.New(\"each option requires a nonempty name\")\n\t\t\t}\n\t\t\tif names[option.Name] {\n\t\t\t\treturn errors.New(\"duplicate option name\")\n\t\t\t}\n\t\t\tif attrView.FilterColorValue(option.Color) != option.Color {\n\t\t\t\treturn errors.New(\"invalid option color\")\n\t\t\t}\n\t\t\tnames[option.Name] = true\n\t\t}\n\t\top.Data = options\n\t\treturn updateAttributeViewColumnOptions(op)\n\t}\n\tif \"optionRemove\" == setting {\n\t\tname, ok := value.(string)\n\t\tif !ok || nil == key.GetOption(name) {\n\t\t\treturn errors.New(\"optionRemove must name an existing option\")\n\t\t}\n\t\top.Data = name","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_key_config.go#L187-L223","documentation":"Every option supplied to the 'options' setting must have a non-empty, non-whitespace Name. SiYuan uses option names as the stored value of select cells, so an unnamed option would corrupt cell data and is rejected during validation.","triggerScenarios":"Updating a select/mselect field's options where an array element is null or its Name is \"\", whitespace-only, or missing from the JSON payload.","commonSituations":"UI code that creates an option row before the user types a name and submits too early; importer producing options with only colors; JSON objects using a wrong property name (e.g. label instead of name) that decodes to an empty Name.","solutions":["Give every option a non-empty Name (trimmed) before sending","Filter out null/incomplete entries from the array client-side","Check the JSON property is exactly \"name\" (av.SelectOption field)"],"exampleFix":"// before\n[{\"color\":\"1\"},{\"name\":\"  \"}]\n// after\n[{\"name\":\"Todo\",\"color\":\"1\"},{\"name\":\"Done\",\"color\":\"3\"}]","handlingStrategy":"validation","validationCode":"const valid = opts => opts.every(o => o && typeof o.name === \"string\" && o.name.trim() !== \"\");\nif (!valid(options)) throw new Error(\"all options need a nonempty name\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Disable the submit button until every option row has a name","Trim and check names before serialization"],"tags":["attribute-view","select-options","validation"],"backgroundTag":"empty-required-field","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}