mattermost-community/focalboard · error
cannot replace blockID %s: %w
Error message
cannot replace blockID %s: %w
What it means
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.
Source
Thrown at server/services/store/sqlstore/data_migrations.go:115
blocksByID := map[string][]*model.Block{}
for _, block := range blocks {
blocksByID[block.ID] = append(blocksByID[block.ID], block)
}
for _, blocks := range blocksByID {
for i, block := range blocks {
if i == 0 {
// do nothing for the first ID, only updating the others
continue
}
newID := utils.NewID(model.BlockType2IDType(block.Type))
if err := s.replaceBlockID(tx, block.ID, newID, block.WorkspaceID); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
s.logger.Error("Unique IDs transaction rollback error", mlog.Err(rollbackErr), mlog.String("methodName", "replaceBlockID"))
}
return fmt.Errorf("cannot replace blockID %s: %w", block.ID, err)
}
}
}
if err := s.setSystemSetting(tx, UniqueIDsMigrationKey, strconv.FormatBool(true)); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
s.logger.Error("Unique IDs transaction rollback error", mlog.Err(rollbackErr), mlog.String("methodName", "setSystemSetting"))
}
return fmt.Errorf("cannot mark migration as completed: %w", err)
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("cannot commit unique IDs transaction: %w", err)
}
s.logger.Debug("Unique IDs migration finished successfully")
return nil
}View on GitHub (pinned to a84bbb65e3)
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.
Example fix
// before SELECT * FROM information_schema.foreign_keys -- after failure on blockID X -- after -- find orphaned references and repair, then retry: DELETE FROM history_blocks WHERE block_id = 'X' AND parent_id IS NULL; -- re-run store.RunUniqueIDsMigration()
Defensive patterns
Strategy: validation
Validate before calling
-- before running the migration, check for orphaned references: SELECT hb.block_id FROM history_blocks hb LEFT JOIN blocks b ON b.id = hb.block_id WHERE b.id IS NULL;
Type guard
func isReplaceBlockIDError(err error) (string, bool) {
if err != nil && strings.Contains(err.Error(), "cannot replace blockID ") {
parts := strings.SplitN(err.Error(), "cannot replace blockID ", 2)
id := strings.Fields(parts[1])[0]
return id, true
}
return "", false
} Try / catch
err := store.RunUniqueIDsMigration()
if err != nil {
if blockID, ok := isReplaceBlockIDError(err); ok {
// inspect all tables referencing blockID, repair rows, then re-run
log.Printf("failed replacing block %s: %v", blockID, errors.Unwrap(err))
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- cannot get blocks with same ID: %w
- cannot mark migration as completed: %w
- cannot save member %s while inserting board %s: %w
- cannot get migration state: %w
- cannot commit unique IDs transaction: %w
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/77a0411a401258d8.
Report an issue: GitHub.