gastownhall/beads · error

checking schema migration work: %w

Error message

checking schema migration work: %w

What it means

This error wraps a failure of `migrationWorkNeeded` — the pre-flight query that decides whether any schema migrations must run. MigrateUp calls it before doing any work so it can short-circuit and still commit seeded dolt_ignore patterns; failing here aborts the whole migration pass.

Source

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

func MigrateUpTo(ctx context.Context, db DBConn, maxVersion int) (int, error) {
	applied, _, err := mainSource.migrate(ctx, db, maxVersion)
	return applied, err
}

func MigrateUp(ctx context.Context, db DBConn) (int, error) {
	// Re-assert the canonical dolt_ignore patterns before anything else, and
	// in particular before the migrationWorkNeeded short-circuit: a database
	// whose migration cursors arrived at-latest without executing the seeding
	// migrations (out-of-band table copy) reports no work needed and
	// would otherwise never be healed.
	seedChanged, err := seedDoltIgnorePatterns(ctx, db)
	if err != nil {
		return 0, err
	}

	needed, err := migrationWorkNeeded(ctx, db)
	if err != nil {
		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)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause for the underlying SQL failure
  2. Ensure no other bd process is migrating concurrently (the advisory lock path serializes, but direct calls bypass it)
  3. Verify schema_migrations is readable and the Dolt server is healthy
  4. Retry MigrateUp once transient conditions clear

Example fix

// before: concurrent migrate calls collide
err := schema.MigrateUp(ctx, db)
// after: use the locked wrapper
err := schema.MigrateUpWithLock(ctx, db)
Defensive patterns

Strategy: retry

Validate before calling

// verify schema state is queryable before a migration pass
if _, err := db.ExecContext(ctx, "SELECT 1 FROM schema_migrations LIMIT 1"); err != nil {
	return fmt.Errorf("schema not queryable: %w", err)
}

Try / catch

_, err := schema.MigrateUp(ctx, db)
if err != nil && strings.Contains(err.Error(), "checking schema migration work") {
	// transient server/lock issue: back off and retry once
	time.Sleep(backoff)
	_, err = schema.MigrateUpWithLock(ctx, db)
}

Prevention

When it happens

Trigger: Calling MigrateUp (directly or via MigrateUpWithLock) when the migration-work check queries schema state (current version vs. available migrations) and the underlying SQL fails — unreadable schema_migrations, locked working set, or context cancellation.

Common situations: Dolt server unavailable or restarting; concurrent bd process holding the migration or working-set lock; corrupt schema_migrations table; context deadline exceeded on slow networked Dolt.

Related errors


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