gastownhall/beads · error

schema skew check: %w

Error message

schema skew check: %w

What it means

This error wraps a failure to read the database's current schema version (`CurrentVersion` querying `schema_migrations`) during the forward schema-skew check. The check guards against running a stale binary against a newer database; this wrapper means the version could not be read at all, before any skew comparison was made.

Source

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

// IsSchemaSkewError reports whether err (or any error it wraps) is a
// *SchemaSkewError.
func IsSchemaSkewError(err error) bool {
	var e *SchemaSkewError
	return errors.As(err, &e)
}

// checkSchemaSkew queries the DB's current schema version and returns a
// *SchemaSkewError if the DB is ahead of the binary. Returns nil for a fresh
// DB (version=0) or when BD_IGNORE_SCHEMA_SKEW=1 (prints a warning instead).
func checkSchemaSkew(ctx context.Context, db DBConn) error {
	// CurrentVersion treats a missing schema_migrations table as version 0, so
	// this is safe to call before migrations have created the table: a
	// brand-new database (version 0) falls through the no-op check below. That
	// matters on the writable open path, where the guard runs before initSchema
	// creates the table on a fresh database.
	currentVersion, err := CurrentVersion(ctx, db)
	if err != nil {
		return fmt.Errorf("schema skew check: %w", err)
	}
	if currentVersion == 0 || currentVersion <= LatestVersion() {
		return nil
	}
	if os.Getenv("BD_IGNORE_SCHEMA_SKEW") == "1" {
		fmt.Fprintf(os.Stderr,
			"Warning: schema skew ignored — database (v%d) is ahead of binary (v%d); some queries may fail\n",
			currentVersion, LatestVersion())
		return nil
	}
	return &SchemaSkewError{DBVersion: currentVersion, BinaryVersion: LatestVersion()}
}

// CheckForwardDrift reports a *SchemaSkewError when the database's schema
// version is AHEAD of the binary's (forward drift). It accepts any DBConn (a
// pooled *sql.DB or a pinned *sql.Conn), so both the read-only store path
// (where MigrateUp is skipped) and the writable open path (where MigrateUp
// no-ops on a forward-drifted DB rather than erroring) can fail fast before a

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause for the real failure (lock, corruption, context deadline)
  2. Verify the Dolt server is running and `SELECT MAX(version) FROM schema_migrations` executes
  3. Retry after transient conditions clear (locks, restarts)
  4. If schema_migrations is corrupt, restore from backup or re-clone
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the version table is readable before the drift check
var v int
if err := db.QueryRowContext(ctx, "SELECT COALESCE(MAX(version),0) FROM schema_migrations").Scan(&v); err != nil {
	return fmt.Errorf("cannot read schema version: %w", err)
}

Type guard

func isSchemaSkewCheckFailure(err error) bool {
	return err != nil && strings.Contains(err.Error(), "schema skew check:")
}

Try / catch

if err := CheckForwardDrift(ctx, db); err != nil {
	if schema.IsSchemaSkewError(err) {
		// handle skew (upgrade binary or BD_IGNORE_SCHEMA_SKEW=1)
	} else {
		// version read itself failed: check server/locks
		fmt.Fprintln(os.Stderr, err)
	}
}

Prevention

When it happens

Trigger: Calling CheckForwardDrift (or the writable open path that runs checkSchemaSkew) when the `schema_migrations` table exists but is unreadable: connection failure, context cancellation, corrupted table, or a locked Dolt working set.

Common situations: Dolt server crashed or restarting mid-command; read-only open against a corrupt repo; another process holding an exclusive lock; interrupted migration leaving schema_migrations inconsistent.

Related errors


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