siyuan-note/siyuan · error
database entry [ ] already exists
Error message
database entry [%s] already exists
What it means
During transaction replay (undo/redo of an 'insert database entries' operation), the kernel re-applies a snapshot of previously inserted rows. Before restoring, it scans the current attribute view for any value whose BlockID is already in the snapshot's item list; if one exists, restoring would duplicate the row, so it aborts with this error. It is an internal consistency guard ensuring idempotent replay of entry insertion.
Solutions
- Check the current database for rows with those block IDs and remove the duplicates before retrying the transaction
- Clear the conflicting transaction history (undo the intermediate operations) so replay no longer collides
- Avoid inserting rows bound to existing block IDs that already appear in the same database; let the kernel generate fresh item IDs
- If triggered by sync, resolve the sync conflict so both sides agree on which rows exist
Example fix
// before: re-inserting rows whose block IDs still exist
attrsView.InsertRows(existingBlockIDs...)
// after: only insert IDs not already present in the database
ids := filter(existingBlockIDs, func(id string) bool { return current.GetBlockValue(id) == nil })
attrsView.InsertRows(ids...) Defensive patterns
Strategy: try-catch
Validate before calling
// client-side: ensure target IDs are not already rows in the database
const exists = await getAttrView(avID);
const dup = exists.keyValues.flatMap(kv => kv.values.map(v => v.blockID)).filter(id => itemIDs.includes(id));
if (dup.length) throw new Error(`rows already present: ${dup.join(',')}`); Try / catch
try { await insertAttrViewBlock(avID, blockID, items); } catch (e) { if (/database entry \[.+\] already exists/.test(e.message)) { await removeDuplicateRows(avID, itemIDs); retry(); } else throw e; } Prevention
- Do not re-insert rows with block IDs that may already exist in the same database
- Minimize interleaved undo/redo edits between delete and re-insert of the same rows
- Resolve sync conflicts promptly so replay state stays consistent
When it happens
Trigger: Replaying a doInsertAttrViewBlock operation whose target rows were re-created (same BlockIDs already present in the attribute view) between the original deletion and the replay — e.g. an undo/redo sequence that re-inserts entries that were later re-added with the same block IDs.
Common situations: Undo/redo history interleaved with other edits; rows restored by sync or another transaction before the replay runs; a plugin or script inserting rows with explicit block IDs that collide with the replayed snapshot.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- database entry binding
- database field [ ] changed since entries were deleted
- attribute view not found
- cannot remove primary key field
- clone attribute view value
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/22955dc0b8318d49.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/attribute_view_items.go:294
return err
}
}
return nil
}
func (tx *Transaction) restoreAttributeViewItems(op *Operation) error {
state := op.attributeViewItems
if !tx.isReplay || op.AvID != state.AvID {
return fmt.Errorf("invalid database entry replay")
}
current, err := tx.readAttributeViewItems(state)
if err != nil {
return err
}
for _, kv := range current.KeyValues {
for _, value := range kv.Values {
if slices.Contains(state.ItemIDs, value.BlockID) {
return fmt.Errorf("database entry [%s] already exists", value.BlockID)
}
}
}
if err = validateAttributeViewItemKeys(current, state); err != nil {
return err
}
for _, kv := range state.Keys {
for _, value := range kv.Values {
if value.Type != av.KeyTypeBlock || value.IsDetached || value.Block == nil {
continue
}
tree, loadErr := tx.loadTree(value.Block.ID)
if loadErr != nil {
return loadErr
}
if err = validateAttributeViewBinding(state.AvID, tree); err != nil {
return err
}View on GitHub (pinned to 9f775e8a12)