gastownhall/beads · error
probing %s existence: %w
Error message
probing %s existence: %w
What it means
currentVersion first probes cursor-table existence with a guaranteed-to-succeed INFORMATION_SCHEMA COUNT(*) query — deliberately, because a failing statement poisons a pooled Dolt connection's catalog snapshot for the life of the session (be-bv7x). If even this safe probe fails, the error is wrapped as `probing <cursor> existence: <cause>`, indicating a connection/server-level fault rather than schema state.
Source
Thrown at internal/storage/schema/schema.go:1220
if err != nil {
return false
}
return current >= m.latest()
}
func (m migrationSource) currentVersion(ctx context.Context, db DBConn) (int, error) {
// Probe existence with a query that always SUCCEEDS before ever issuing one
// that can fail. A Dolt session that issues a failing statement stays
// pinned to its pre-statement catalog snapshot, so a bare SELECT against a
// not-yet-created cursor table poisons the pooled connection: tables
// created afterwards on other connections stay invisible to this one for
// the rest of its life in the pool (be-bv7x).
var cursorExists int
if err := db.QueryRowContext(ctx,
"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?",
m.cursorTable,
).Scan(&cursorExists); err != nil {
return 0, fmt.Errorf("probing %s existence: %w", m.cursorTable, err)
}
if cursorExists == 0 {
return 0, nil
}
var current int
err := db.QueryRowContext(ctx, "SELECT COALESCE(MAX(version), 0) FROM "+m.cursorTable).Scan(¤t)
if err != nil && err != sql.ErrNoRows {
if dberrors.IsTableNotExist(err) {
return 0, nil
}
return 0, fmt.Errorf("reading %s version: %w", m.cursorTable, err)
}
if current == 0 {
return 0, nil
}
// A missing cursor TABLE already meant "nothing applied". A cursor whose
// tables are absent means the same thing and was previously believedView on GitHub (pinned to 71377f2769)
Solutions
- Retry with fresh connections; if errors mention 'bad connection' or 'invalid connection', recycle the pool.
- Verify the DSN names an existing schema so DATABASE() resolves correctly.
- Add startup retry/backoff so MigrateUp waits for the DB to become reachable.
- Confirm the DB user can read INFORMATION_SCHEMA (usually implicit, but restricted setups can deny it).
Example fix
// before
if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM information_schema.tables WHERE ...", m.cursorTable).Scan(&cursorExists); err != nil {
return 0, fmt.Errorf("probing %s existence: %w", m.cursorTable, err)
}
// after
if err := db.PingContext(ctx); err != nil {
return 0, fmt.Errorf("database unreachable before probing %s: %w", m.cursorTable, err)
}
if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM information_schema.tables WHERE ...", m.cursorTable).Scan(&cursorExists); err != nil {
return 0, fmt.Errorf("probing %s existence: %w", m.cursorTable, err)
} Defensive patterns
Strategy: retry
Validate before calling
// wait for the DB before starting migrations
for i := 0; i < 30; i++ {
if err := db.PingContext(ctx); err == nil { break }
time.Sleep(2 * time.Second)
} Type guard
func isConnErr(err error) bool {
var netErr net.Error
return errors.As(err, &netErr) || strings.Contains(err.Error(), "connection refused")
} Try / catch
err := MigrateUp(ctx, db)
if err != nil && strings.Contains(err.Error(), "probing ") {
// existence-probe failure is connectivity-level; wait and retry
time.Sleep(5 * time.Second)
err = MigrateUp(ctx, db)
} Prevention
- Add startup readiness checks so migrations run only after the DB is reachable.
- Verify the DSN includes a valid database name (DATABASE() must resolve).
- Keep pool connection lifetimes below server wait_timeout.
- Confirm the DB user can query information_schema.
When it happens
Trigger: The `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?` scan fails: dead pooled connection, context timeout, permission denial on INFORMATION_SCHEMA, or server unavailability.
Common situations: App boots while the database is still starting (container orchestration race); stale pool connections after a server restart; wait_timeout reaping idle connections; wrong DSN database so DATABASE() is null/unexpected.
Related errors
- snapshotting dirty tables before %s: %w
- no database connection available (%s)
- dolt server connection failed: %w
- failed to reach the workspace identity: %v
- failed to migrate credential keys: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f6f1ac517bdecbe1.
Report an issue: GitHub.