immich-app/immich · error

Migration " " failed

Error message

Migration "${result.migrationName}" failed

What it means

After running Kysely migrations to latest, the repository inspects each migration result. A migration with status 'Error' logs this warning; the accompanying migrator error is then logged and rethrown downstream. It signals that a specific named migration failed to apply.

Solutions

  1. Read the accompanying 'Migrations failed: <error>' log for the root cause and fix the underlying SQL/data issue
  2. Restore from backup and retry the upgrade if the schema is half-migrated
  3. Ensure the database user has CREATE/ALTER privileges in the public schema
  4. Increase statement timeouts (statement_timeout=0) for long migrations and restart the server to retry
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight privilege check before migrating
await sql`SELECT has_schema_privilege(current_user, 'public', 'CREATE') AS ok`.execute(db);
await sql`SELECT has_table_privilege(current_user, 'migrations', 'INSERT') AS ok`.execute(db);

Try / catch

try {
  await db.runMigrations();
} catch (err) {
  logger.error(`Migration failed: ${err}. Fix root cause or restore backup before restarting.`);
  process.exit(1); // don't boot a half-migrated server
}

Prevention

When it happens

Trigger: runMigrations() calls migrator.migrateToLatest() and one or more migration scripts failed — e.g. SQL error, lock timeout, or a migration already half-applied.

Common situations: Upgrading Immich versions where a new migration conflicts with existing data/schema; database permissions missing for ALTER/CREATE; partially applied migration from a crashed previous run; slow migrations killed by connection timeout.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/143b0a5e13c643c6. Report an issue: GitHub.

Appendix: source

Thrown at server/src/repositories/database.repository.ts:392

    const { count } = await this.db
      .selectFrom(this.db.dynamic.table(table).as('t'))
      .select((eb) => eb.fn.countAll<number>().as('count'))
      .executeTakeFirstOrThrow();
    return count;
  }

  async runMigrations(): Promise<number> {
    this.logger.log('Running migrations');

    const migrator = this.createMigrator();

    const { error, results = [] } = await migrator.migrateToLatest();

    for (const result of results) {
      if (result.status === 'Success') {
        this.logger.log(`Migration "${result.migrationName}" succeeded`);
      } else if (result.status === 'Error') {
        this.logger.warn(`Migration "${result.migrationName}" failed`);
      }
    }

    if (error) {
      this.logger.error(`Migrations failed: ${error}`);

      const missing =
        error instanceof Error ? error.message.match(/previously executed migration (.+) is missing/u) : null;
      if (missing) {
        throw new Error(
          `Migration "${missing[1]}" was already applied to this database but is not in this version of Immich (${serverVersion}). ` +
            `This usually means the database was migrated by a newer version. Downgrades are not supported.`,
          { cause: error },
        );
      }

      throw error;
    }

View on GitHub (pinned to e55ac299a4)