gastownhall/beads · error

ErrScan

ErrScan

Error message

scan error

What it means

ErrScan is the dolt storage layer's sentinel for failures converting database rows into Go values — rows.Scan failing because column types or count don't match the destination (e.g. NULL into a non-nullable field, column added/renamed by a schema change). wrapScanError embeds it in the chain for errors.Is classification.

Source

Thrown at internal/storage/dolt/errors.go:28

	mysql "github.com/go-sql-driver/mysql"

	"github.com/steveyegge/beads/internal/storage"
	"github.com/steveyegge/beads/internal/storage/dberrors"
)

// Sentinel errors for the dolt storage layer.
// These complement the storage-level sentinels (storage.ErrNotFound, etc.)
// with dolt-specific error types.
var (
	// ErrTransaction indicates a transaction begin/commit/rollback failure.
	ErrTransaction = errors.New("transaction error")

	// ErrQuery indicates a database query failure.
	ErrQuery = errors.New("query error")

	// ErrScan indicates a failure scanning database rows into Go values.
	ErrScan = errors.New("scan error")

	// ErrExec indicates a database exec (INSERT/UPDATE/DELETE) failure.
	ErrExec = errors.New("exec error")

	// ErrDanglingReference indicates that the pre-push integrity check detected
	// missing chunks in the local Dolt noms store. The push was aborted to
	// prevent propagating the corruption to the remote. Run bd dolt verify
	// to diagnose and recover.
	ErrDanglingReference = errors.New("dangling chunk reference")

	// ErrFSCKTimeout indicates that the pre-push integrity check (dolt fsck) did
	// not complete within the configured timeout. The push was aborted without
	// verifying chunk integrity — the store is not necessarily corrupt. Large
	// stores can be shrunk with `dolt gc` (or `CALL DOLT_GC()` on a running
	// sql-server); the timeout can be raised via the BEADS_FSCK_TIMEOUT
	// environment variable.
	ErrFSCKTimeout = errors.New("pre-push integrity check timed out")

View on GitHub (pinned to 71377f2769)

Solutions

  1. Compare your bd binary version with the database schema version (bd doctor) — upgrade or migrate so they match
  2. Read the wrapped error for the exact column mismatch: errors.Is(err, dolt.ErrScan) then unwrap
  3. If caused by version rollback, re-upgrade the binary or restore a matching backup (bd backup restore)
  4. Fix the NULL source or change the scan destination to a pointer/sql.Null* type if you own the query

Example fix

// before
var assignee string
if err := row.Scan(&id, &assignee); err != nil { return err } // fails on NULL assignee
// after
var assignee sql.NullString
if err := row.Scan(&id, &assignee); err != nil {
    if errors.Is(err, dolt.ErrScan) { /* schema drift: check bd doctor */ }
    return err
}
a := assignee.String // empty when NULL
Defensive patterns

Strategy: type-guard

Type guard

func isScanError(err error) bool {
    return errors.Is(err, dolt.ErrScan)
}

Try / catch

if err := store.List(ctx); err != nil {
    if errors.Is(err, dolt.ErrScan) {
        return fmt.Errorf("schema mismatch between binary and database; run bd doctor / re-migrate: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Any dolt-backed read where rows.Scan fails after a successful query: schema drift between the running code and the database (a column added, removed, or type-changed), unexpected NULL in a column scanned into a non-pointer type, or a column order/count mismatch in hand-written SELECTs.

Common situations: Rolling back the bd binary to an older version against a newer migrated database; a partially applied or failed migration; manually editing the schema; database written by a newer bd version and read by an older one.

Related errors


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