siyuan-note/siyuan · error

existing back relation is invalid

Error message

existing back relation is invalid

What it means

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.

Solutions

  1. Inspect the destination view's key with the stored BackKeyID and repair or delete the broken pair
  2. Remove the stale relation on the source key and recreate the two-way relation from scratch (which allocates a fresh BackKeyID)
  3. If only isTwoWay is changing, verify both sides' Relation.AvID and Relation.BackKeyID mirror each other before updating
Defensive patterns

Strategy: try-catch

Validate before calling

// Inspect the destination back key before updating
const dest = await api.getAttributeView(destAvID);
const backKey = dest.keys.find(k => k.id === sourceKey.relation?.backKeyID);
const valid = backKey && backKey.type === 'relation' &&
  backKey.relation?.avID === avID && backKey.relation?.backKeyID === keyID;

Try / catch

try {
  await api.updateAttributeViewKeyConfig({avID, keyID, relation: cfg});
} catch (e) {
  if (e.message.includes('existing back relation is invalid')) {
    // clear the stale relation and recreate the two-way pair
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/attribute_view_key_config.go:300

	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)
			if nil != getErr || av.KeyTypeRelation != backKey.Type || nil == backKey.Relation ||
				backKey.Relation.AvID != op.AvID || backKey.Relation.BackKeyID != key.ID {
				return errors.New("existing back relation is invalid")
			}
			if "" == config.BackKeyName {
				op.Name = backKey.Name
			}
		}
	}
	err = updateAttributeViewColRelation(op)
	if nil == err {
		ReloadAttrView(config.AvID)
		if nil != key.Relation && key.Relation.AvID != config.AvID {
			ReloadAttrView(key.Relation.AvID)
		}
	}
	return err
}

func updateAttributeViewKeyRollup(attrView *av.AttributeView, key *av.Key, op *Operation, value any) error {
	if av.KeyTypeRollup != key.Type {

View on GitHub (pinned to 9f775e8a12)