siyuan-note/siyuan · error
config must contain exactly one setting; use separate calls…
Error message
config must contain exactly one setting; use separate calls for multiple settings
What it means
UpdateAttributeViewKeyConfig changes exactly one field (column) configuration per call. The config map must therefore contain exactly one key; passing zero or multiple settings is rejected up front so each change maps to one UI/undo operation and related data is maintained deterministically.
Solutions
- Split the update into one API call per setting, e.g. one call for "name" and a separate one for "desc"
- Validate len(config) == 1 in client code before issuing the request
- If the empty-map case occurs, check upstream filtering logic that builds the config object
Example fix
// before
updateKeyConfig(avID, keyID, {"name": "Title", "desc": "main"})
// after
updateKeyConfig(avID, keyID, {"name": "Title"})
updateKeyConfig(avID, keyID, {"desc": "main"}) Defensive patterns
Strategy: validation
Validate before calling
function assertSingleSetting(config) { if (!config || typeof config !== 'object' || Object.keys(config).length !== 1) throw new Error('config must contain exactly one setting'); } Try / catch
try { await updateKeyConfig(avID, keyID, cfg); } catch (e) { if (/exactly one setting/.test(e.message)) { for (const k of Object.keys(cfg)) await updateKeyConfig(avID, keyID, { [k]: cfg[k] }); } else throw e; } Prevention
- Build one call per setting in your API wrapper
- Assert Object.keys(config).length === 1 before sending
- Never send an empty config object
When it happens
Trigger: Calling UpdateAttributeViewKeyConfig (via the databaseKeyUpdate API path) with a config map like {"name":"x","desc":"y"}, or with an empty map {}.
Common situations: Plugin authors batching multiple column-property updates in one request; generic config editors passing a whole settings object; accidental empty payload after filtering.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Field [keyIDs] is required
- field name must not be empty
- Field [ ] is required
- invalid width for attribute view column
- numberFormat requires a number field and a supported format
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/f88d086bfffd7a52.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/attribute_view_key_config.go:30
"bytes"
"encoding/json"
"errors"
"fmt"
"slices"
"strings"
"github.com/88250/lute/ast"
"github.com/siyuan-note/siyuan/kernel/av"
)
var AttributeViewKeyNumberFormats = []string{"", "commas", "percent", "USD", "CNY", "EUR", "GBP", "JPY", "RUB", "INR", "KRW", "TRY", "CAD", "CHF", "THB", "AUD", "HKD", "TWD", "MOP", "SGD", "NZD", "ILS", "SKK"}
var AttributeViewKeyRollupOperators = []string{"", "Unique values", "Count all", "Count values", "Count unique values", "Count empty", "Count not empty", "Percent empty", "Percent not empty", "Percent unique values", "Sum", "Average", "Median", "Min", "Max", "Range", "Earliest", "Latest", "Checked", "Unchecked", "Percent checked", "Percent unchecked"}
// UpdateAttributeViewKeyConfig 每次修改一个字段配置,先校验参数,再复用界面操作维护关联数据。
func UpdateAttributeViewKeyConfig(avID, keyID string, config map[string]any) (err error) {
if 1 != len(config) {
return errors.New("config must contain exactly one setting; use separate calls for multiple settings")
}
attrView, err := av.ParseAttributeView(avID)
if nil != err {
return err
}
key, err := attrView.GetKey(keyID)
if nil != err {
return err
}
op := &Operation{AvID: avID, ID: keyID, Typ: string(key.Type), Name: key.Name}
for setting, value := range config {
switch setting {
case "name", "type", "icon", "desc", "numberFormat", "dateFormat", "template", "renderTemplate":
text, ok := value.(string)
if !ok {
return fmt.Errorf("%s must be a string", setting)
}
op.Data, op.Format = text, textView on GitHub (pinned to 9f775e8a12)