siyuan-note/siyuan · error

related database entry

Error message

related database entry [%s] is missing

What it means

When re-establishing a two-way relation for restored rows, each target block ID referenced by the historical relation value must exist as a row in the destination database (dest.GetBlockValue(targetID) != nil). If a referenced target row was itself deleted and cannot be found, the symmetric link would dangle, so the rollback aborts with the missing target ID.

Solutions

  1. Restore the related document/entry first (roll back its history) so the target row exists, then roll back this document
  2. Manually re-create the missing entry in the destination database with the target block ID, then retry
  3. Remove the dangling relation value from the historical snapshot JSON so the restore can proceed without that link
  4. Re-link the relation manually after the document rollback, deleting the offending history value
Defensive patterns

Strategy: validation

Validate before calling

// Go: verify relation targets exist before rollback
for _, targetID := range value.Relation.BlockIDs {
    if dest.GetBlockValue(targetID) == nil {
        // target row missing; restore it first or drop the link
    }
}

Type guard

if dest.GetBlockValue(targetID) == nil {
    return ErrMissingRelatedEntry
}

Try / catch

err := tx.restoreBoundAttributeViewHistory(tree, historyDir)
if err != nil && strings.Contains(err.Error(), "is missing") {
    // restore the related document first, or clean the snapshot's relation value
}

Prevention

When it happens

Trigger: RollbackDocHistory where a restored row's two-way relation value references a row in another database that no longer exists — e.g. the related entry was deleted and its own document/database also cleaned up, or the target database's rows were purged between deletion and rollback.

Common situations: Cascading deletions where the related block/entry was removed too; rolling back only one of two interlinked documents; detached entries removed by other edits; snapshots referencing entries in databases that were since emptied.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/attribute_view_block_history.go:233

			if relation == nil || !relation.IsTwoWay {
				continue
			}
			for _, value := range kv.Values {
				if !slices.Contains(itemIDs, value.BlockID) || value.Relation == nil || len(value.Relation.BlockIDs) == 0 {
					continue
				}
				dest, err := load(relation.AvID)
				if err != nil {
					return err
				}
				back, err := dest.GetKeyValues(relation.BackKeyID)
				if err != nil || back.Key.Relation == nil || !back.Key.Relation.IsTwoWay ||
					back.Key.Relation.AvID != id || back.Key.Relation.BackKeyID != kv.Key.ID {
					return errors.New("database back relation changed since document deletion")
				}
				for _, targetID := range value.Relation.BlockIDs {
					if dest.GetBlockValue(targetID) == nil {
						return fmt.Errorf("related database entry [%s] is missing", targetID)
					}
					backValue := back.GetValue(targetID)
					if backValue == nil {
						backValue = &av.Value{ID: ast.NewNodeID(), KeyID: back.Key.ID, BlockID: targetID,
							Type: av.KeyTypeRelation, Relation: &av.ValueRelation{}}
						back.Values = append(back.Values, backValue)
					}
					if backValue.Relation == nil {
						return errors.New("database back relation value is invalid")
					}
					if !slices.Contains(backValue.Relation.BlockIDs, value.BlockID) {
						backValue.Relation.BlockIDs = append(backValue.Relation.BlockIDs, value.BlockID)
					}
				}
			}
		}
	}
	if len(restoredItems) == 0 {

View on GitHub (pinned to 9f775e8a12)