{"record":{"id":"cea784f5ff7e5cb9","repo":"siyuan-note/siyuan","slug":"invalid-database-entry-replay","errorCode":null,"errorMessage":"invalid database entry replay","messagePattern":"invalid database entry replay","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_items.go","lineNumber":285,"sourceCode":"\t\t\tfor _, value := range kv.Values {\n\t\t\t\tif !value.IsDetached && value.Block != nil {\n\t\t\t\t\tblockIDs = append(blockIDs, value.Block.ID)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor _, id := range blockIDs {\n\t\tif err := tx.rememberAttributeViewMutationTree(id); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (tx *Transaction) restoreAttributeViewItems(op *Operation) error {\n\tstate := op.attributeViewItems\n\tif !tx.isReplay || op.AvID != state.AvID {\n\t\treturn fmt.Errorf(\"invalid database entry replay\")\n\t}\n\tcurrent, err := tx.readAttributeViewItems(state)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, kv := range current.KeyValues {\n\t\tfor _, value := range kv.Values {\n\t\t\tif slices.Contains(state.ItemIDs, value.BlockID) {\n\t\t\t\treturn fmt.Errorf(\"database entry [%s] already exists\", value.BlockID)\n\t\t\t}\n\t\t}\n\t}\n\tif err = validateAttributeViewItemKeys(current, state); err != nil {\n\t\treturn err\n\t}\n\tfor _, kv := range state.Keys {\n\t\tfor _, value := range kv.Values {\n\t\t\tif value.Type != av.KeyTypeBlock || value.IsDetached || value.Block == nil {","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_items.go#L267-L303","documentation":"restoreAttributeViewItems re-inserts rows recorded in a deletion snapshot during undo replay. It first requires tx.isReplay to be true and op.AvID to match the snapshot's AvID (state.AvID); anything else — calling it outside replay, or an operation whose AvID was changed or detached from its snapshot — is rejected as 'invalid database entry replay' because the recorded rows cannot be safely restored into a different database or context.","triggerScenarios":"doInsertAttrViewBlock replay where the operation's AvID was altered between capture and replay, the attributeViewItems snapshot is missing or belongs to another database, or restoreAttributeViewItems is invoked with tx.isReplay false (direct call instead of replay).","commonSituations":"A plugin manually composes insertAttrViewBlock undo operations without the kernel-managed snapshot; operations reordered/re-targeted by custom transaction code; undo stack entries from a different workspace or synced from another client with different database IDs.","solutions":["Let the kernel capture the deletion snapshot automatically (do not hand-build insertAttrViewBlock inverses)","Keep op.AvID identical to the snapshot's AvID throughout the transaction lifecycle","Clear the corrupt undo entry (or rebuild the undo stack) and repeat the delete/undo cycle cleanly"],"exampleFix":"// before\nop.AvID = otherAvID // retargeted inverse operation\n// after\nif op.AvID == snapshot.AvID && tx.isReplay {\n    return tx.restoreAttributeViewItems(op)\n}\n","handlingStrategy":"try-catch","validationCode":"if !tx.isReplay || op.attributeViewItems == nil || op.AvID != op.attributeViewItems.AvID {\n    return fmt.Errorf(\"skip entry restore: snapshot/operation mismatch\")\n}","typeGuard":"func entrySnapshotValid(op *model.Operation) bool {\n    s := op.attributeViewItems\n    return s != nil && op.AvID == s.AvID\n}","tryCatchPattern":"if err := tx.restoreAttributeViewItems(op); err != nil {\n    if strings.Contains(err.Error(), \"invalid database entry replay\") {\n        // drop the stale inverse operation and rebuild the undo stack\n        return nil\n    }\n    return err\n}","preventionTips":["Do not hand-construct insertAttrViewBlock inverses; rely on kernel snapshot capture","Never retarget AvID on captured undo operations","Keep undo history within a single workspace; clear it after major sync merges"],"tags":["database","attribute-view","undo-redo","replay"],"backgroundTag":"invalid-state-transition","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"}