{"record":{"id":"27b788b8ae64f731","repo":"siyuan-note/siyuan","slug":"database-field-s-changed-since-document-deletion","errorCode":null,"errorMessage":"database field [%s] changed since document deletion","messagePattern":"database field \\[(.+?)\\] changed since document deletion","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_block_history.go","lineNumber":184,"sourceCode":"\t\t\tif _, exists := bound[id][primary.Block.ID]; !exists || current.GetBlockValueByBoundID(primary.Block.ID) != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif current.GetBlockValue(primary.BlockID) != nil {\n\t\t\t\treturn fmt.Errorf(\"database entry [%s] has a different binding\", primary.BlockID)\n\t\t\t}\n\t\t\titemIDs = append(itemIDs, primary.BlockID)\n\t\t}\n\t\tif len(itemIDs) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, kv := range historical.KeyValues {\n\t\t\tfor _, value := range kv.Values {\n\t\t\t\tif !slices.Contains(itemIDs, value.BlockID) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfield, err := current.GetKeyValues(kv.Key.ID)\n\t\t\t\tif err != nil || field.Key.Type != kv.Key.Type || !reflect.DeepEqual(field.Key.Relation, kv.Key.Relation) {\n\t\t\t\t\treturn fmt.Errorf(\"database field [%s] changed since document deletion\", kv.Key.ID)\n\t\t\t\t}\n\t\t\t\tif field.GetValue(value.BlockID) == nil {\n\t\t\t\t\tfield.Values = append(field.Values, value.Clone())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor _, view := range current.Views {\n\t\t\tif old := historical.GetView(view.ID); old != nil {\n\t\t\t\tview.ItemIDs = restoreAttributeViewItemOrder(view.ItemIDs, old.ItemIDs, itemIDs)\n\t\t\t\tfor _, group := range view.Groups {\n\t\t\t\t\tif oldGroup := old.GetGroupByID(group.ID); oldGroup != nil {\n\t\t\t\t\t\tgroup.GroupItemIDs = restoreAttributeViewItemOrder(group.GroupItemIDs, oldGroup.GroupItemIDs, itemIDs)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor _, itemID := range itemIDs {\n\t\t\tif covers := historical.CardCoverPositions[itemID]; covers != nil {","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_block_history.go#L166-L202","documentation":"When merging historical rows back, restoreBoundAttributeViewHistory checks each field (key) in the snapshot against the corresponding live field: the key must exist, have the same type, and an identical Relation definition (deep-equal). If the live database's field schema changed since the document was deleted (type changed, relation re-pointed, or key removed), historical values cannot be safely re-attached and the rollback aborts.","triggerScenarios":"RollbackDocHistory on a document with attribute-view rows, where between deletion and rollback a field in the bound database was deleted, changed type (e.g. text→number), or its relation settings (AvID/BackKeyID/IsTwoWay) were modified, so GetKeyValues(kv.Key.ID) fails or the type/relation comparison fails.","commonSituations":"User edited the database schema after deleting a document and then rolled back; migration or plugin scripts altering field definitions; restoring across workspace versions where serialization of Relation differs; merging snapshots from databases that were since restructured.","solutions":["Restore the database field to its pre-deletion definition (same key ID, type, and relation settings) and retry the rollback","Pick an earlier document-history version taken before the schema change","If the schema change is intended, manually copy the historical values into the new field instead of relying on rollback","Export the historical row data from the snapshot JSON for reference, then rebuild rows manually"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Go: before rollback, verify field schema matches snapshot\nfield, err := current.GetKeyValues(kv.Key.ID)\nschemaOK := err == nil && field.Key.Type == kv.Key.Type &&\n    reflect.DeepEqual(field.Key.Relation, kv.Key.Relation)","typeGuard":null,"tryCatchPattern":"err := tx.restoreBoundAttributeViewHistory(tree, historyDir)\nif err != nil && strings.Contains(err.Error(), \"changed since document deletion\") {\n    // restore the field definition or pick an earlier history version\n}","preventionTips":["Freeze database schema changes until pending rollbacks are done","Document field ID/type/relation before deleting documents for later restore","Avoid plugins/API scripts that mutate key definitions","Roll back before restructuring the database"],"tags":["database","history","attribute-view","schema-change"],"backgroundTag":"schema-validation-failed","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"}