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
- 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
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
- 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
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
- attribute view [ ] has no block key
- 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/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)