{"record":{"id":"7fff2064e4dda7c3","repo":"siyuan-note/siyuan","slug":"database-entry-binding-s-changed","errorCode":null,"errorMessage":"database entry binding [%s] changed","messagePattern":"database entry binding \\[(.+?)\\] changed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_binding_undo.go","lineNumber":58,"sourceCode":"\t\tif !tx.isReplay || state.avID != op.AvID || state.before.BlockID != op.PreviousID {\n\t\t\treturn fmt.Errorf(\"invalid database binding replay\")\n\t\t}\n\t\tcurrent, err := tx.readAttributeViewForMutation(state.avID, state.blockID, state.boxID)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif state.duplicateItemID != \"\" {\n\t\t\top.RetData = map[string]any{\"targetItemID\": state.duplicateItemID, \"duplicate\": true}\n\t\t\treturn nil\n\t\t}\n\t\texpected, desired := state.before, state.after\n\t\tif op.attributeViewBindingUndo {\n\t\t\texpected, desired = desired, expected\n\t\t}\n\t\tvalue := current.GetBlockValue(expected.BlockID)\n\t\tif value == nil || value.Block == nil || value.ID != expected.ID || value.KeyID != expected.KeyID ||\n\t\t\tvalue.IsDetached != expected.IsDetached || value.Block.ID != expected.Block.ID {\n\t\t\treturn fmt.Errorf(\"database entry binding [%s] changed\", expected.BlockID)\n\t\t}\n\t\tif err = tx.applyAttributeViewBinding(current, value, desired, state); err != nil {\n\t\t\treturn err\n\t\t}\n\t\top.RetData = map[string]any{\"targetItemID\": value.BlockID, \"duplicate\": false}\n\t\treturn nil\n\t}\n\n\tvar inverse *Operation\n\tif tx.fromAPI && !tx.isReplay {\n\t\tfor _, undo := range tx.UndoOperations {\n\t\t\tif undo.Action == \"replaceAttrViewBlock\" && undo.AvID == op.AvID &&\n\t\t\t\tundo.PreviousID == op.PreviousID && undo.attributeViewBinding == nil {\n\t\t\t\tinverse = undo\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_binding_undo.go#L40-L76","documentation":"During a database binding replacement (bind/replace block in an attribute view) the transaction verifies the current on-disk row value still matches the snapshot recorded when the operation was queued. If the value is missing or its ID, key ID, detached flag, or bound block ID changed, the transaction aborts to avoid overwriting a concurrent modification.","triggerScenarios":"replaceAttributeViewBinding executed after another transaction already changed the row: the block was rebound elsewhere, the row was detached/re-keyed, or the entry was deleted so GetBlockValue(expected.BlockID) returns nil or a value with a different Value.ID/KeyID/Block.ID than the captured expectation.","commonSituations":"Two windows or a sync job editing the same database concurrently; undo/redo racing with live edits; replaying an operation against an attribute view that was re-indexed or restored from history between queueing and execution.","solutions":["Retry the operation after the conflicting change settles (close other editors/sync, then re-bind)","Reload the attribute view so a fresh snapshot is captured and redo the replace","Recreate the affected database row if its value record is permanently out of sync","If this appears during undo/redo only, report the transaction-log sequence as a bug"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const current = av.rows.find(r => r.id === expected.blockID);\nif (!current || current.valueID !== expected.id || current.keyID !== expected.keyID) {\n  refreshAttributeView(avID);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.replaceAttrViewBlock(op);\n} catch (e) {\n  if (/database entry binding .* changed/.test(e.msg)) {\n    await reloadAV(avID);\n    await api.replaceAttrViewBlock(op);\n  }\n}","preventionTips":["Avoid concurrent edits to the same database row from multiple clients","Complete or cancel pending sync before rebinding blocks","Reload the attribute view after history restores before issuing more binding ops","Serialize programmatic binding operations through one queue"],"tags":["database","concurrency","optimistic-lock","attribute-view"],"backgroundTag":"conflicting-concurrent-modification","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"}