mattermost-community/focalboard · error
cannot mark migration as completed
Error message
cannot mark migration as completed: %w
What it means
Error from SQLStore.RunUniqueIDsMigration (server/services/store/data_migrations.go:124). After replacing duplicate IDs, the migration marks completion by writing UniqueIDsMigrationKey=true via setSystemSetting(tx, ...). If that write fails, the transaction is rolled back (all ID replacements undone) and the error is wrapped as 'cannot mark migration as completed'.
Solutions
- Check the wrapped cause; if it is a connection timeout, increase idle/transaction timeouts and re-run.
- Ensure the DB user can INSERT/UPDATE the SystemSettings table.
- Run the migration during a maintenance window so the transaction finishes quickly; the rollback makes retry safe (idempotent flag).
- Avoid PgBouncer transaction-pooling misconfigurations that kill long transactions; use a dedicated session pool for migrations.
- If 'Unique IDs transaction rollback error' also appears in logs, verify no manual cleanup is needed before retrying.
Example fix
// before SET GLOBAL wait_timeout = 28800; -- default, too short for long txns // after SET GLOBAL wait_timeout = 86400; SET GLOBAL max_allowed_packet = 64M; -- then re-run: store.RunUniqueIDsMigration()
Defensive patterns
Strategy: retry
Validate before calling
var canWrite bool
if err := db.QueryRow("SELECT has_table_privilege('system_settings','INSERT','current_user')").Scan(&canWrite); err != nil || !canWrite { /* grant write before migrating */ } Type guard
func isMigrationFinalizeError(err error) bool {
return err != nil && strings.Contains(err.Error(), "cannot mark migration as completed")
} Try / catch
err := store.RunUniqueIDsMigration()
if err != nil {
if isMigrationFinalizeError(err) {
// store already rolled back; fix timeouts/permissions and retry safely
log.Println("migration rolled back, retryable:", errors.Unwrap(err))
}
return err
} Prevention
- Raise idle-transaction/timeout settings before long migrations
- Use a direct DB connection (not transaction-pooled) for migrations
- Grant the app user write access to SystemSettings
- Run migrations single-instance to avoid settings-row contention
When it happens
Trigger: Running RunUniqueIDsMigration when the final setSystemSetting upsert into SystemSettings fails: connection loss, deadlock on the settings row, permissions failure, or settings table schema issues — after the (possibly lengthy) ID replacement work has already succeeded inside the transaction.
Common situations: Long-running migration holding the transaction open until the connection is dropped by a proxy/idle timeout (MySQL wait_timeout, PgBouncer) right before the final write; DB user lacking UPDATE rights on SystemSettings; concurrent migration runs contending on the settings row.
Related errors
- cannot get blocks with same ID
- cannot replace blockID
- cannot commit category UUIDs transaction
- cannot commit unique IDs transaction
- cannot get migration state
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/048c8f9276ef3d17.
Report an issue: GitHub.
Appendix: source
Thrown at server/services/store/sqlstore/data_migrations.go:124
// 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
}
// RunCategoryUUIDIDMigration takes care of deriving the categories
// from the boards and its memberships. The name references UUID
// because of the preexisting purpose of this migration, and has been
// preserved for compatibility with already migrated instances.
func (s *SQLStore) RunCategoryUUIDIDMigration() error {
setting, err := s.GetSystemSetting(CategoryUUIDIDMigrationKey)
if err != nil {
return fmt.Errorf("cannot get migration state: %w", err)View on GitHub (pinned to a84bbb65e3)