gastownhall/beads · error

schema behind-drift check: %w

Error message

schema behind-drift check: %w

What it means

This error wraps a failure to read `MAX(version)` from `schema_migrations` during the behind-drift check. CheckBehindDrift runs on read-only open paths that cannot migrate; this wrapper means the drift check itself failed because the schema_migrations table could not be queried, not that the DB is behind.

Source

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

// *SchemaBehindError.
func IsSchemaBehindError(err error) bool {
	var e *SchemaBehindError
	return errors.As(err, &e)
}

// CheckBehindDrift returns a *SchemaBehindError when the database's schema
// version is behind the binary's. Used by read-only opens, which skip
// MigrateUp by design (bd-6dnrw.32) — the paths that previously auto-migrated
// foreign databases (GH#3231) now need a clear open-time failure instead of
// unknown-column errors at query time. BD_IGNORE_SCHEMA_SKEW=1 downgrades it
// to a warning, mirroring forward drift. A fresh DB (version 0) is reported
// as behind too: it has no readable schema at all.
func CheckBehindDrift(ctx context.Context, db *sql.DB) error {
	var currentVersion int
	if err := db.QueryRowContext(ctx,
		"SELECT COALESCE(MAX(version), 0) FROM schema_migrations",
	).Scan(&currentVersion); err != nil {
		return fmt.Errorf("schema behind-drift check: %w", err)
	}
	if currentVersion >= LatestVersion() {
		return nil
	}
	if os.Getenv("BD_IGNORE_SCHEMA_SKEW") == "1" {
		fmt.Fprintf(os.Stderr,
			"Warning: schema skew ignored — database (v%d) is behind binary (v%d) and was opened read-only; some queries may fail\n",
			currentVersion, LatestVersion())
		return nil
	}
	return &SchemaBehindError{DBVersion: currentVersion, BinaryVersion: LatestVersion()}
}

type dirtyTableState struct {
	staged bool
}

var doltStatusTableNameRE = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause to identify the underlying query failure
  2. Confirm the Dolt server is reachable and the repo's working set is clean (`dolt status`)
  3. Wait for any concurrent migration process to finish, then retry
  4. Restore from backup if schema_migrations is corrupt
Defensive patterns

Strategy: try-catch

Validate before calling

var v int
if err := db.QueryRowContext(ctx, "SELECT COALESCE(MAX(version),0) FROM schema_migrations").Scan(&v); err != nil {
	return err // cannot even evaluate behind-drift
}

Type guard

func isBehindDriftCheckFailure(err error) bool {
	return err != nil && strings.Contains(err.Error(), "behind-drift check:")
}

Try / catch

if err := CheckBehindDrift(ctx, db); err != nil {
	if schema.IsSchemaBehindError(err) {
		// run a write command once to migrate
	} else {
		// query failed: server/lock/corruption issue
		return err
	}
}

Prevention

When it happens

Trigger: Calling CheckBehindDrift on a database where the `schema_migrations` SELECT fails: table missing/corrupt, connection error, context cancellation, or a Dolt working-set lock held by another process.

Common situations: Read-only open against a workspace mid-migration by another process; corrupted repo; Dolt server unavailable; networked Dolt with a dropped connection.

Related errors


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