{"record":{"id":"b1efc9cbd5ed7e04","repo":"siyuan-note/siyuan","slug":"relation-requires-avid-and-istwoway","errorCode":null,"errorMessage":"relation requires avID and isTwoWay","messagePattern":"relation requires avID and isTwoWay","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_key_config.go","lineNumber":279,"sourceCode":"\t}\n\top.Data = map[string]any{\"oldName\": option.Name, \"newName\": name, \"newColor\": color, \"newDesc\": desc}\n\treturn updateAttributeViewColumnOption(op)\n}\n\nfunc updateAttributeViewKeyRelation(key *av.Key, op *Operation, value any) error {\n\tif av.KeyTypeRelation != key.Type {\n\t\treturn errors.New(\"relation requires a relation field\")\n\t}\n\tvar config struct {\n\t\tAvID        string `json:\"avID\"`\n\t\tIsTwoWay    *bool  `json:\"isTwoWay\"`\n\t\tBackKeyName string `json:\"backKeyName\"`\n\t}\n\tif err := decodeAttributeViewKeyConfig(value, &config); nil != err {\n\t\treturn err\n\t}\n\tif nil == config.IsTwoWay || \"\" == config.AvID {\n\t\treturn errors.New(\"relation requires avID and isTwoWay\")\n\t}\n\tdest, err := av.ParseAttributeView(config.AvID)\n\tif nil != err {\n\t\treturn err\n\t}\n\t// 先认证已有目标，避免无法读取旧关联时静默跳过回链清理。\n\tif nil != key.Relation && \"\" != key.Relation.AvID {\n\t\tif _, err := av.ParseAttributeView(key.Relation.AvID); nil != err {\n\t\t\treturn err\n\t\t}\n\t}\n\top.ID, op.KeyID, op.Format = config.AvID, key.ID, key.Name\n\top.IsTwoWay, op.Name = *config.IsTwoWay, config.BackKeyName\n\tif op.IsTwoWay {\n\t\top.BackRelationKeyID = ast.NewNodeID()\n\t\tif nil != key.Relation && key.Relation.IsTwoWay && key.Relation.AvID == config.AvID {\n\t\t\top.BackRelationKeyID = key.Relation.BackKeyID\n\t\t\tbackKey, getErr := dest.GetKey(op.BackRelationKeyID)","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_key_config.go#L261-L297","documentation":"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.","triggerScenarios":"Calling UpdateAttributeViewKeyConfig with relation config where the JSON payload lacks \"isTwoWay\" or \"avID\", or avID is an empty string.","commonSituations":"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.","solutions":["Include both avID (target attribute view ID) and isTwoWay (boolean) in the relation config payload","Check JSON field names match exactly: avID, isTwoWay, backKeyName","Read the target avID from the relation target view rather than leaving it blank for 'same view'"],"exampleFix":"// before\npayload := map[string]any{\"avID\": \"\"} // isTwoWay missing\n// after\npayload := map[string]any{\"avID\": destAvID, \"isTwoWay\": true, \"backKeyName\": \"Related items\"}","handlingStrategy":"validation","validationCode":"if (!cfg.avID || typeof cfg.isTwoWay !== 'boolean') {\n  throw new Error('relation config needs avID and isTwoWay');\n}","typeGuard":"function hasRequiredRelationConfig(cfg) {\n  return typeof cfg === 'object' && cfg !== null &&\n    typeof cfg.avID === 'string' && cfg.avID.length > 0 &&\n    typeof cfg.isTwoWay === 'boolean';\n}","tryCatchPattern":"try {\n  await api.updateAttributeViewKeyConfig({avID, keyID, relation: cfg});\n} catch (e) {\n  if (e.message.includes('relation requires avID and isTwoWay')) {\n    // fill required fields and retry once\n  }\n}","preventionTips":["Always send both avID and isTwoWay in relation payloads","Match JSON field names exactly (camelCase)","Build payloads from a typed schema, not ad-hoc objects"],"tags":["attribute-view","relation","missing-field"],"backgroundTag":"missing-required-argument","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"}