siyuan-note/siyuan · error

database field [ ] changed since entries were deleted

Error message

database field [%s] changed since entries were deleted

What it means

validateAttributeViewItemKeys compares each key snapshot (taken when entries were removed or inserted) against the current database: the key must still exist with the same type and an identical Relation config (compared with reflect.DeepEqual). If the field was deleted, retyped, or its relation configuration changed, restoring the saved entries would write into a structurally different field, so the replay aborts.

Solutions

  1. Undo the column type/relation change so the field matches the snapshot before replaying entry operations
  2. Re-create a field with the same ID, type, and relation config if it was deleted
  3. Re-add the removed entries manually instead of replaying the old transaction
  4. When scripting schema changes, check for pending undo history on the database first and avoid interleaving type changes with row edits
Defensive patterns

Strategy: validation

Validate before calling

// compare current field type/relation against a saved snapshot before restoring entries
const cur = await getAttrView(avID);
for (const k of snapshotKeys) {
  const now = cur.keyTypes[k.id];
  if (!now || now.type !== k.type || JSON.stringify(now.relation) !== JSON.stringify(k.relation)) throw new Error(`field ${k.id} changed`);
}

Try / catch

try { await restoreEntries(snapshot); } catch (e) { if (/changed since entries were deleted/.test(e.message)) { await undoSchemaChange(); retryRestore(); } else throw e; }

Prevention

When it happens

Trigger: Replaying prepareAttributeViewItemRemoval or restoreAttributeViewItems after the captured fields were deleted, type-converted (e.g. text to number), or had their Relation (AvID/BackKeyID/IsTwoWay) reconfigured since the snapshot was taken.

Common situations: Undoing an entry removal after later editing the column type or relation wiring; a plugin renamed/retyped columns via API between operations; sync merged a schema change into the database.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — 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/2f59f14adb930a35. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view_items.go:420

		attrs[av.NodeAttrNameAvs] = strings.Trim(strings.Join(ids, ","), ",")
		attrs[av.NodeAttrViewNames] = getAvNames(attrs[av.NodeAttrNameAvs])
		if err = setNodeAttrsWithTx(tx, node, tree, attrs); err != nil {
			return err
		}
	}
	refreshRelatedSrcAvsInBlock(state.AvID, state.BlockID, tx)
	if err = tx.replayAttributeViewItemConfiguration(state, true); err != nil {
		return err
	}
	op.RetData = &insertAttrViewBlockResult{InsertedItemIDs: append([]string(nil), state.ItemIDs...)}
	return nil
}

func validateAttributeViewItemKeys(current *av.AttributeView, state *attributeViewItemsSnapshot) error {
	for _, kv := range state.Keys {
		key, err := current.GetKey(kv.Key.ID)
		if err != nil || key.Type != kv.Key.Type || !reflect.DeepEqual(key.Relation, kv.Key.Relation) {
			return fmt.Errorf("database field [%s] changed since entries were deleted", kv.Key.ID)
		}
	}
	return nil
}

func restoreAttributeViewItemOrder(current, original, itemIDs []string) []string {
	for index, id := range original {
		if !slices.Contains(itemIDs, id) || slices.Contains(current, id) {
			continue
		}
		position := -1
		for previous := index - 1; previous >= 0; previous-- {
			if found := slices.Index(current, original[previous]); found >= 0 {
				position = found + 1
				break
			}
		}
		if position < 0 {

View on GitHub (pinned to 9f775e8a12)