gastownhall/beads · error

reading pre-migration status: %w

Error message

reading pre-migration status: %w

What it means

This error wraps a failure of `dirtyTables` — MigrateUp reads the pre-migration dirty-table state to enforce its pre-existing-dirty guards (a dirty working set before the pass is an error condition). Failing here aborts the migration before any step runs.

Source

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

		return 0, fmt.Errorf("checking schema migration work: %w", err)
	}
	if !needed {
		// No migration pass will run, so nothing downstream commits the seed:
		// it would sit as an uncommitted working-set diff until an unrelated
		// write/pull sweeps it into its commit (and a read-only repo carries
		// it indefinitely). Commit it here, scoped and labeled, so the
		// out-of-band-copy heal converges in one pass.
		if seedChanged {
			if err := commitSeededDoltIgnore(ctx, db); err != nil {
				return 0, err
			}
		}
		return 0, nil
	}

	dirtyBeforeAll, err := dirtyTables(ctx, db, false)
	if err != nil {
		return 0, fmt.Errorf("reading pre-migration status: %w", err)
	}
	// dolt_ignore is pass-owned state: seedDoltIgnorePatterns above may have
	// just dirtied it on an under-seeded database. Exempting it from the
	// pre-existing-dirty guards (like the aux-rekey tables below) keeps the
	// pending-migration and changed-signature gates off it.
	delete(dirtyBeforeAll, "dolt_ignore")
	if err := unstagePreExistingTables(ctx, db, dirtyBeforeAll); err != nil {
		return 0, fmt.Errorf("unstaging pre-migration tables: %w", err)
	}
	// The seed must not ride the migration pass: every step of the pass
	// commits atomically, and a pass killed between steps must leave a CLEAN
	// working set (the #4566 self-heal contract) — but the seeded dolt_ignore
	// rows would stay dirty until the pass's final commit, so an interrupted
	// retry sees a dirty working set and refuses to converge. Commit the seed
	// scoped and labeled now, after pre-existing staged tables were unstaged
	// (so nothing else rides into the commit) and before the first step runs.
	if seedChanged {
		if err := commitSeededDoltIgnore(ctx, db); err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause for the underlying failure
  2. Run `dolt status` manually against the repo to check working-set health
  3. Wait for concurrent Dolt writers to finish, then retry
  4. If a previous crashed pass left the set inconsistent, follow the #4566 self-heal path (clean or commit the working set) and re-run

Example fix

// before: dirtyTables blocked by another writer
$ bd migrate // hangs/fails reading status
// after: ensure single writer, then retry
$ pkill -f 'bd migrate' && bd migrate
Defensive patterns

Strategy: try-catch

Validate before calling

// check working set is readable and clean before migrating
rows, err := db.QueryContext(ctx, "CALL DOLT_STATUS()")
if err != nil { return err }
// inspect dirty state; abort or clean before MigrateUp

Try / catch

_, err := schema.MigrateUp(ctx, db)
if err != nil && strings.Contains(err.Error(), "reading pre-migration status") {
	// dirtyTables read failed: check server and concurrent writers
	return fmt.Errorf("cannot read working-set status; resolve and retry: %w", err)
}

Prevention

When it happens

Trigger: MigrateUp calling dirtyTables(ctx, db, false) and the underlying `dolt status`-equivalent query fails — Dolt server error, locked working set, corrupted working-set metadata, or context cancellation.

Common situations: Another Dolt client holds the working set; a crashed prior migration left inconsistent working-set state; networked Dolt connection dropped mid-read; server freshly restarted and not serving status.

Related errors


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