gastownhall/beads · error

ignored migrations: %w

Error message

ignored migrations: %w

What it means

MigrateUp runs schema migrations in two passes: a main-source pass over user tables and an 'ignored source' pass that manages dolt_ignore'd internal tables (e.g. ignored_schema_migrations). This error wraps any failure from the ignored-source migrate step, so the caller knows the main migrations may have already applied but the ignored-table migrations did not complete. The error is deliberately fatal: callers must not treat the open/migrate as successful because a half-applied pass could be checkpointed by a reconcile commit.

Source

Thrown at internal/storage/schema/schema.go:713

		return applied, fmt.Errorf("checking dirty tables against pending ignored migrations: %w", err)
	}
	if len(touchedIgnoredDirtyTables) > 0 {
		// Deliberately a plain, untyped error (unlike the main-source guard
		// above, which returns *DirtyTablesError): this check fires mid-pass,
		// after the main-source migrations have already applied. A lenient
		// caller (embeddeddolt's openReadOnlyCommand / openWorkingSetReconcile
		// intents) skipping this and returning as if the open succeeded would
		// let a reconcile commit checkpoint a half-applied migration pass.
		// The ignored source also tracks bd-internal state (dolt_ignore'd
		// tables like ignored_schema_migrations), not expected user data, so
		// there is no dirty-commit recovery story to support here the way
		// there is for the main-source guard (#4566 scope).
		return applied, fmt.Errorf("pending ignored schema migrations alter pre-existing dirty tables: %s", strings.Join(touchedIgnoredDirtyTables, ", "))
	}

	appliedIgnored, ignoredColumnAdded, err := ignoredSource.migrate(ctx, db, 0)
	if err != nil {
		return applied, fmt.Errorf("ignored migrations: %w", err)
	}
	if err := unstageIgnoredTables(ctx, db); err != nil {
		return applied, fmt.Errorf("unstaging ignored migration tables: %w", err)
	}

	if applied == 0 && !backfilled && appliedIgnored == 0 && !mainColumnAdded && !ignoredColumnAdded {
		return applied, nil
	}
	changedDirtyTables, err := changedDirtyTableSignatures(ctx, db, dirtyBeforeSignatures)
	if err != nil {
		return applied, fmt.Errorf("checking pre-existing dirty table diffs: %w", err)
	}
	if len(changedDirtyTables) > 0 {
		return applied, fmt.Errorf("pre-existing dirty tables changed during schema migration: %s", strings.Join(changedDirtyTables, ", "))
	}

	staged, err := stageSchemaTables(ctx, db, dirtyBefore)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped cause (%w) for the underlying SQL error and fix that first — this error is only a wrapper around the ignored-source migrate failure
  2. Inspect the dolt_ignore'd internal tables (e.g. ignored_schema_migrations) with SHOW TABLES / dolt status and repair or restore from a backup if corrupted
  3. Re-run MigrateUp after the underlying failure is resolved; the migration cursors determine which statements re-apply
  4. If a clone is non-converged, re-clone from a healthy remote instead of hand-patching the ignored tables
  5. Do not commit or reconcile on this error — retry from a state where the whole pass can run cleanly

Example fix

// before: treating open failure as soft and committing anyway
applied, err := schema.MigrateUp(ctx, db)
if err != nil {
    log.Warn("migrate failed, continuing")
    reconcileCommit() // dangerous: half-applied pass
}
// after: abort on ignored-migration errors before any commit
applied, err := schema.MigrateUp(ctx, db)
if err != nil {
    return fmt.Errorf("database open aborted: %w", err)
}
reconcileCommit()
Defensive patterns

Strategy: try-catch

Validate before calling

// Before migrating, check both sources are at a migratable state
ok, err := schema.MigrationWorkNeeded(ctx, db)
if err != nil {
    return fmt.Errorf("cannot assess migration state: %w", err)
}
if ok {
    log.Println("migration required; ensure backup exists and no dirty ignored tables")
}

Try / catch

applied, err := schema.MigrateUp(ctx, db)
if err != nil {
    var msg string
    if errors.Unwrap(err) != nil {
        msg = errors.Unwrap(err).Error()
    }
    // Match the wrapper text to branch on the ignored-pass failure
    if strings.Contains(err.Error(), "ignored migrations:") {
        return fmt.Errorf("ignored-source migration failed (%s); aborting open, no commit attempted", msg)
    }
    return err
}

Prevention

When it happens

Trigger: Calling MigrateUp/MigrateUpWithLock when ignoredSource.migrate fails — i.e. a DDL statement in the ignored-source migration set errors (SQL syntax/dialect failure, locked or corrupted internal dolt_ignore'd tables, connection dropped mid-pass, or a migration applied out of order on a non-converged clone).

Common situations: Opening a beads database whose Dolt working set is in a bad state (corrupt ignored_schema_migrations table), running an older binary's migration set against a newer database or vice versa, network/lock failures between the main pass and the ignored pass, or an interrupted prior upgrade leaving the ignored source mid-migration.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/529b9b5035a2b6f9. Report an issue: GitHub.