invoke-ai/InvokeAI · critical · MigrationError

Database is at version

Error message

Database is at version {version}, expected {expected}

What it means

_run_migration wraps each migration in a transaction and verifies the database's current user_version matches the migration's declared from_version before executing. If the DB is at a different version, the migration's assumptions are violated and a MigrationError is raised, aborting (and rolling back) the migration.

Solutions

  1. Bring the InvokeAI install to the version matching the DB's migration state
  2. Restore a DB backup whose version matches the expected from_version
  3. Check PRAGMA user_version on the DB and confirm which build should run it
  4. Back up the DB before retrying migrations

Example fix

# inspect version
sqlite3 /data/invokeai/invokeai.db 'PRAGMA user_version;'
# before: running mismatched build
# after: upgrade so app version == db version
pip install -U invokeai && invokeai-web --root /data/invokeai
Defensive patterns

Strategy: try-catch

Validate before calling

import sqlite3
cursor = sqlite3.connect(db_path).cursor()
version = cursor.execute("PRAGMA user_version").fetchone()[0]
assert version == expected_from_version, f"db at {version}, migration expects {expected_from_version}"

Try / catch

try:
    services.run_migrations()
except MigrationError as e:
    if "expected" in str(e) and "Database is at version" in str(e):
        logger.critical("Version mismatch between app and DB: %s", e)
        raise
    raise

Prevention

When it happens

Trigger: run_migrations applying a migration whose from_version is set but the sqlite PRAGMA user_version differs — e.g. DB already partially migrated, migrated by a different version, or starting from a non-zero DB created elsewhere.

Common situations: Running an older InvokeAI binary against a DB migrated by a newer one; restoring an old DB snapshot mid-migration; copying a DB between installs with divergent histories.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/a421f31b0c501763. Report an issue: GitHub.

Appendix: source

Thrown at invokeai/app/services/shared/sqlite_migrator/sqlite_migrator_impl.py:101

        if self._db._db_path is not None:
            timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
            self._backup_path = self._db._db_path.parent / f"{self._db._db_path.stem}_backup_{timestamp}.db"
            self._logger.info(f"Backing up database to {str(self._backup_path)}")
            with closing(sqlite3.connect(self._backup_path)) as backup_conn:
                self._db._conn.backup(backup_conn)
        else:
            self._logger.info("Using in-memory database, no backup needed")

    def _run_migration(self, migration: Migration) -> None:
        """Runs a single migration."""
        try:
            # Using sqlite3.Connection as a context manager commits a the transaction on exit, or rolls it back if an
            # exception is raised.
            with self._db._conn as conn:
                cursor = conn.cursor()
                self._create_applied_migrations_table(cursor)
                if migration.from_version is not None and self._get_current_version(cursor) != migration.from_version:
                    raise MigrationError(
                        f"Database is at version {self._get_current_version(cursor)}, expected {migration.from_version}"
                    )
                self._logger.debug(f"Running migration '{migration.id}'")

                # Run the actual migration
                migration.callback(cursor)

                if migration.to_version is not None:
                    cursor.execute("INSERT INTO migrations (version) VALUES (?);", (migration.to_version,))
                cursor.execute(
                    "INSERT INTO applied_migrations (migration_id, legacy_version) VALUES (?, ?);",
                    (migration.id, migration.to_version),
                )

                self._logger.debug(f"Successfully ran migration '{migration.id}'")
        # We want to catch *any* error, mirroring the behaviour of the sqlite3 module.
        except Exception as e:
            # The connection context manager has already rolled back the migration, so we don't need to do anything.

View on GitHub (pinned to 0b6a024f2f)