siyuan-note/siyuan · error

relation requires avID and isTwoWay

Error message

relation requires avID and isTwoWay

What it means

A relation key update requires the destination attribute view ID (avID) and the two-way flag (isTwoWay). This error is thrown when the decoded relation config omits isTwoWay (nil pointer) or has an empty avID, since both are mandatory to establish or update the relation link.

Solutions

  1. Include both avID (target attribute view ID) and isTwoWay (boolean) in the relation config payload
  2. Check JSON field names match exactly: avID, isTwoWay, backKeyName
  3. Read the target avID from the relation target view rather than leaving it blank for 'same view'

Example fix

// before
payload := map[string]any{"avID": ""} // isTwoWay missing
// after
payload := map[string]any{"avID": destAvID, "isTwoWay": true, "backKeyName": "Related items"}
Defensive patterns

Strategy: validation

Validate before calling

if (!cfg.avID || typeof cfg.isTwoWay !== 'boolean') {
  throw new Error('relation config needs avID and isTwoWay');
}

Type guard

function hasRequiredRelationConfig(cfg) {
  return typeof cfg === 'object' && cfg !== null &&
    typeof cfg.avID === 'string' && cfg.avID.length > 0 &&
    typeof cfg.isTwoWay === 'boolean';
}

Try / catch

try {
  await api.updateAttributeViewKeyConfig({avID, keyID, relation: cfg});
} catch (e) {
  if (e.message.includes('relation requires avID and isTwoWay')) {
    // fill required fields and retry once
  }
}

Prevention

When it happens

Trigger: Calling UpdateAttributeViewKeyConfig with relation config where the JSON payload lacks "isTwoWay" or "avID", or avID is an empty string.

Common situations: Partially filled API payloads where callers assume defaults exist; JSON field name typos (e.g. "avid", "twoWay"); clients written against an older config shape before isTwoWay became required.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/attribute_view_key_config.go:279

	}
	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 {
		if _, err := av.ParseAttributeView(key.Relation.AvID); nil != err {
			return err
		}
	}
	op.ID, op.KeyID, op.Format = config.AvID, key.ID, key.Name
	op.IsTwoWay, op.Name = *config.IsTwoWay, config.BackKeyName
	if op.IsTwoWay {
		op.BackRelationKeyID = ast.NewNodeID()
		if nil != key.Relation && key.Relation.IsTwoWay && key.Relation.AvID == config.AvID {
			op.BackRelationKeyID = key.Relation.BackKeyID
			backKey, getErr := dest.GetKey(op.BackRelationKeyID)

View on GitHub (pinned to 9f775e8a12)