{"record":{"id":"e678cf28c52a7f14","repo":"siyuan-note/siyuan","slug":"existing-back-relation-is-invalid","errorCode":null,"errorMessage":"existing back relation is invalid","messagePattern":"existing back relation is invalid","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_key_config.go","lineNumber":300,"sourceCode":"\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)\n\t\t\tif nil != getErr || av.KeyTypeRelation != backKey.Type || nil == backKey.Relation ||\n\t\t\t\tbackKey.Relation.AvID != op.AvID || backKey.Relation.BackKeyID != key.ID {\n\t\t\t\treturn errors.New(\"existing back relation is invalid\")\n\t\t\t}\n\t\t\tif \"\" == config.BackKeyName {\n\t\t\t\top.Name = backKey.Name\n\t\t\t}\n\t\t}\n\t}\n\terr = updateAttributeViewColRelation(op)\n\tif nil == err {\n\t\tReloadAttrView(config.AvID)\n\t\tif nil != key.Relation && key.Relation.AvID != config.AvID {\n\t\t\tReloadAttrView(key.Relation.AvID)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc updateAttributeViewKeyRollup(attrView *av.AttributeView, key *av.Key, op *Operation, value any) error {\n\tif av.KeyTypeRollup != key.Type {","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_key_config.go#L282-L318","documentation":"When updating a two-way relation pointing at the same target view as before, the code reuses the existing back-relation key ID and verifies that the destination key is a valid two-way relation pointing back to this key. If the back key is missing, is not a relation, or its Relation does not point back (wrong AvID or BackKeyID), the existing back relation is considered corrupt and this error is thrown instead of silently recreating it.","triggerScenarios":"Updating a two-way relation key whose stored BackKeyID refers to a deleted key, a non-relation key, or a relation key whose AvID/BackKeyID no longer matches this key — typically after manual data edits, merge conflicts, or partial sync.","commonSituations":"Data modified by older SiYuan versions with different back-relink semantics; a user deleted the paired key on the target view outside the two-way update; corrupted .av files restored from backups.","solutions":["Inspect the destination view's key with the stored BackKeyID and repair or delete the broken pair","Remove the stale relation on the source key and recreate the two-way relation from scratch (which allocates a fresh BackKeyID)","If only isTwoWay is changing, verify both sides' Relation.AvID and Relation.BackKeyID mirror each other before updating"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Inspect the destination back key before updating\nconst dest = await api.getAttributeView(destAvID);\nconst backKey = dest.keys.find(k => k.id === sourceKey.relation?.backKeyID);\nconst valid = backKey && backKey.type === 'relation' &&\n  backKey.relation?.avID === avID && backKey.relation?.backKeyID === keyID;","typeGuard":null,"tryCatchPattern":"try {\n  await api.updateAttributeViewKeyConfig({avID, keyID, relation: cfg});\n} catch (e) {\n  if (e.message.includes('existing back relation is invalid')) {\n    // clear the stale relation and recreate the two-way pair\n  }\n}","preventionTips":["Do not delete one side of a two-way relation manually","Keep both sides' Relation.AvID/BackKeyID mirrored after data imports","Recreate the relation pair if either side fails the back-link validation"],"tags":["attribute-view","relation","corrupt-data"],"backgroundTag":"internal-invariant-violation","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"}