gastownhall/beads · error
scan remote-tracking ref: %w
Error message
scan remote-tracking ref: %w
What it means
ListRemoteRefs iterates rows from dolt_remote_branches and scans each row's name column into a string. This error wraps a rows.Scan failure — the driver could not convert the row value into a *string, or the row is in an unexpected shape. It is thrown so the listing step reports per-row data problems distinctly from query errors.
Source
Thrown at internal/storage/versioncontrolops/remoterefs.go:21
import (
"context"
"fmt"
)
// ListRemoteRefs returns the names of all cached remote-tracking refs
// (e.g. "remotes/origin/main"), sorted by name.
func ListRemoteRefs(ctx context.Context, db DBConn) ([]string, error) {
rows, err := db.QueryContext(ctx, "SELECT name FROM dolt_remote_branches ORDER BY name")
if err != nil {
return nil, fmt.Errorf("list remote-tracking refs: %w", err)
}
defer rows.Close()
var refs []string
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, fmt.Errorf("scan remote-tracking ref: %w", err)
}
refs = append(refs, name)
}
return refs, rows.Err()
}
// PruneRemoteRefs deletes every cached remote-tracking ref and returns the
// names deleted. After a history squash (Flatten/Compact) these refs still
// anchor the pre-squash commit chain, so DOLT_GC treats the entire old history
// as reachable and reclaims nothing (bd-agctw). Pruning is safe on a squashed
// workspace: the refs are local caches only — nothing is deleted on the remote
// itself — and the next push or fetch re-creates them at the new tip.
//
// On error, the returned slice holds the refs deleted before the failure.
func PruneRemoteRefs(ctx context.Context, db DBConn) ([]string, error) {
refs, err := ListRemoteRefs(ctx, db)
if err != nil {
return nil, errView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error to identify the offending column/value type mismatch.
- Run SELECT name FROM dolt_remote_branches manually to find rows with NULL or malformed names and repair or remove them.
- Upgrade or re-initialize the Dolt database if metadata was corrupted by a version change (e.g. after a failed migration).
- Check rows.Err() after iteration to ensure the row set itself is intact.
Example fix
// before
if err := rows.Scan(&name); err != nil {
return nil, fmt.Errorf("scan remote-tracking ref: %w", err)
}
// after: tolerate NULLs with sql.NullString
var name sql.NullString
if err := rows.Scan(&name); err != nil {
return nil, fmt.Errorf("scan remote-tracking ref: %w", err)
}
if !name.Valid { continue } Defensive patterns
Strategy: validation
Validate before calling
rows, err := db.QueryContext(ctx, "SELECT name FROM dolt_remote_branches WHERE name IS NOT NULL ORDER BY name")
if err != nil {
return err
} Try / catch
refs, err := versioncontrolops.ListRemoteRefs(ctx, db)
var scanErr *sql.ScanError
if err != nil && errors.As(err, &scanErr) {
log.Printf("malformed ref row, falling back to raw query: %v", err)
refs, err = queryRefsManually(ctx, db)
} Prevention
- Filter NULL names in the query or use sql.NullString when reading system tables.
- Pin and test against your Dolt engine version; re-check column types after upgrades.
- Check rows.Err() after iterating result sets.
- Repair corrupted metadata promptly instead of letting it accumulate.
When it happens
Trigger: A row in dolt_remote_branches has a NULL or non-string name value that cannot be scanned into a Go string; the driver returns rows in an unexpected column layout after a Dolt engine change.
Common situations: Corrupted or partially-migrated Dolt metadata after an upgrade/downgrade; a Dolt version where dolt_remote_branches exposes different column types; NULL ref names left by an interrupted operation.
Related errors
- scan tag: %w
- failed to open server connection: %w
- failed to begin transaction: %w
- failed to recompute is_blocked: %w
- failed to commit is_blocked repairs: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2bc742111a68dfea.
Report an issue: GitHub.