{"record":{"id":"77a0411a401258d8","repo":"mattermost-community/focalboard","slug":"cannot-replace-blockid-s-w","errorCode":null,"errorMessage":"cannot replace blockID %s: %w","messagePattern":"cannot replace blockID (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/services/store/sqlstore/data_migrations.go","lineNumber":115,"sourceCode":"\n\tblocksByID := map[string][]*model.Block{}\n\tfor _, block := range blocks {\n\t\tblocksByID[block.ID] = append(blocksByID[block.ID], block)\n\t}\n\n\tfor _, blocks := range blocksByID {\n\t\tfor i, block := range blocks {\n\t\t\tif i == 0 {\n\t\t\t\t// do nothing for the first ID, only updating the others\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tnewID := utils.NewID(model.BlockType2IDType(block.Type))\n\t\t\tif err := s.replaceBlockID(tx, block.ID, newID, block.WorkspaceID); err != nil {\n\t\t\t\tif rollbackErr := tx.Rollback(); rollbackErr != nil {\n\t\t\t\t\ts.logger.Error(\"Unique IDs transaction rollback error\", mlog.Err(rollbackErr), mlog.String(\"methodName\", \"replaceBlockID\"))\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"cannot replace blockID %s: %w\", block.ID, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif err := s.setSystemSetting(tx, UniqueIDsMigrationKey, strconv.FormatBool(true)); err != nil {\n\t\tif rollbackErr := tx.Rollback(); rollbackErr != nil {\n\t\t\ts.logger.Error(\"Unique IDs transaction rollback error\", mlog.Err(rollbackErr), mlog.String(\"methodName\", \"setSystemSetting\"))\n\t\t}\n\t\treturn fmt.Errorf(\"cannot mark migration as completed: %w\", err)\n\t}\n\n\tif err := tx.Commit(); err != nil {\n\t\treturn fmt.Errorf(\"cannot commit unique IDs transaction: %w\", err)\n\t}\n\n\ts.logger.Debug(\"Unique IDs migration finished successfully\")\n\treturn nil\n}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/services/store/sqlstore/data_migrations.go#L97-L133","documentation":"Error from SQLStore.RunUniqueIDsMigration (server/services/store/sqlstore/data_migrations.go:115). For each block with a duplicate ID, the migration generates a new ID and calls replaceBlockID(tx, ...) to rewrite the ID across all affected tables within the transaction. Any failure is wrapped with the offending old block ID, after rolling back the whole migration transaction.","triggerScenarios":"Running the unique-IDs migration when replaceBlockID fails for a specific duplicated block: FK constraint violations on child tables referencing the block ID, schema drift (a table still referencing the old ID without an update path), statement timeout, or connection loss mid-transaction.","commonSituations":"Instances with manually manipulated databases or restored partial backups where referential integrity is broken; plugins/older versions that added their own tables keyed by block ID which replaceBlockID does not know about; very large block histories causing per-update timeouts.","solutions":["Inspect the wrapped cause for the failing block ID to find which table/constraint rejected the ID replacement.","Search the schema for tables still referencing the old block ID and update or clean them manually, then re-run the migration.","Restore referential integrity (orphaned child rows) before retrying; the transaction rolls back so state is consistent.","Run during a maintenance window to avoid lock contention and timeouts.","Back up the database before running this migration on large or hand-modified datasets."],"exampleFix":"// before\nSELECT * FROM information_schema.foreign_keys -- after failure on blockID X\n-- after\n-- find orphaned references and repair, then retry:\nDELETE FROM history_blocks WHERE block_id = 'X' AND parent_id IS NULL;\n-- re-run\nstore.RunUniqueIDsMigration()","handlingStrategy":"validation","validationCode":"-- before running the migration, check for orphaned references:\nSELECT hb.block_id FROM history_blocks hb\nLEFT JOIN blocks b ON b.id = hb.block_id\nWHERE b.id IS NULL;","typeGuard":"func isReplaceBlockIDError(err error) (string, bool) {\n\tif err != nil && strings.Contains(err.Error(), \"cannot replace blockID \") {\n\t\tparts := strings.SplitN(err.Error(), \"cannot replace blockID \", 2)\n\t\tid := strings.Fields(parts[1])[0]\n\t\treturn id, true\n\t}\n\treturn \"\", false\n}","tryCatchPattern":"err := store.RunUniqueIDsMigration()\nif err != nil {\n\tif blockID, ok := isReplaceBlockIDError(err); ok {\n\t\t// inspect all tables referencing blockID, repair rows, then re-run\n\t\tlog.Printf(\"failed replacing block %s: %v\", blockID, errors.Unwrap(err))\n\t}\n\treturn err\n}","preventionTips":["Take a DB backup before running the unique-IDs migration","Audit custom/legacy tables referencing block IDs before migrating","Restore referential integrity after partial backups/restores","Schedule migrations in a maintenance window to avoid lock contention"],"tags":["database","migration","transaction","foreign-key","focalboard"],"backgroundTag":"data-migration-replace-failed","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}