siyuan-note/siyuan · error
relation requires a relation field
Error message
relation requires a relation field
What it means
updateAttributeViewKeyRelation handles updates to relation-type keys. This error is thrown when the target key's type is not av.KeyTypeRelation, meaning the caller attempted to apply relation configuration (avID, isTwoWay, backKeyName) to a non-relation field such as text, number, or select.
Solutions
- Verify the key's type is av.KeyTypeRelation before sending relation configuration
- Create a new relation field if a relation is needed, instead of reconfiguring an existing non-relation key
- Re-fetch the key by ID to confirm its current type (it may have changed)
Example fix
// before
UpdateAttributeViewKeyConfig(avID, viewID, &conf.AttributeViewKeyConfig{KeyID: textKeyID, Relation: relCfg})
// after
if key, err := attrView.GetKey(textKeyID); err == nil && key.Type == av.KeyTypeRelation {
UpdateAttributeViewKeyConfig(avID, viewID, &conf.AttributeViewKeyConfig{KeyID: textKeyID, Relation: relCfg})
} Defensive patterns
Strategy: type-guard
Validate before calling
// Verify key type via the API before sending relation config const key = av.keys.find(k => k.id === keyID); const isRelation = key && key.type === 'relation';
Type guard
function isRelationKey(key) {
return !!key && key.type === 'relation';
} Try / catch
try {
await api.updateAttributeViewKeyConfig({avID, keyID, relation: cfg});
} catch (e) {
if (e.message.includes('relation requires a relation field')) {
// key is not a relation; create a relation key instead
}
} Prevention
- Re-read the key's type immediately before config updates
- Never reuse cached key IDs after type changes
- Keep relation config in a code path only reachable for relation keys
When it happens
Trigger: Calling UpdateAttributeViewKeyConfig with operation targeting relation config against a key whose Type != KeyTypeRelation.
Common situations: Using a stale key ID after the field type was changed; confusing a rollup key with a relation key; scripted config that assumes all keys support relation settings.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- block [ ] is not an instance of attribute view [ ]
- database back relation changed since document deletion
- database back relation field
- database back relation value is invalid
- database back relation values
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/abaef6dbb58b3438.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/attribute_view_key_config.go:268
color = *config.Color
if attrView.FilterColorValue(color) != color {
return errors.New("invalid option color")
}
}
if nil != config.Desc {
desc = *config.Desc
}
if name == option.Name {
op.Data = []*av.SelectOption{{Name: name, Color: color, Desc: desc}}
return updateAttributeViewColumnOptions(op)
}
op.Data = map[string]any{"oldName": option.Name, "newName": name, "newColor": color, "newDesc": desc}
return updateAttributeViewColumnOption(op)
}
func updateAttributeViewKeyRelation(key *av.Key, op *Operation, value any) error {
if av.KeyTypeRelation != key.Type {
return errors.New("relation requires a relation field")
}
var config struct {
AvID string `json:"avID"`
IsTwoWay *bool `json:"isTwoWay"`
BackKeyName string `json:"backKeyName"`
}
if err := decodeAttributeViewKeyConfig(value, &config); nil != err {
return err
}
if nil == config.IsTwoWay || "" == config.AvID {
return errors.New("relation requires avID and isTwoWay")
}
dest, err := av.ParseAttributeView(config.AvID)
if nil != err {
return err
}
// 先认证已有目标,避免无法读取旧关联时静默跳过回链清理。
if nil != key.Relation && "" != key.Relation.AvID {View on GitHub (pinned to 9f775e8a12)