gastownhall/beads · error

checkout active branch %q: %w

Error message

checkout active branch %q: %w

What it means

pinStoreBranch keeps each connection pinned to the store's active branch: it reads active_branch() and issues CALL DOLT_CHECKOUT on the target connection. If that checkout fails (e.g. the branch name no longer exists or the connection's session is in a bad state), the error is wrapped with the branch name so you know which branch could not be selected.

Source

Thrown at internal/storage/dolt/store.go:1071

// pool behind s.db is effectively single-connection. Checkout() leases one
// connection from that pool (s.db.Conn), runs DOLT_CHECKOUT on it and returns
// it — the branch stays with that physical connection, because checkout is
// per-connection session state. The pool defaults to defaultMaxOpenConns (10,
// overridable by BEADS_DOLT_MAX_CONNS or dolt.max-conns), so on a genuinely
// multi-connection pool this read may be served by a sibling connection that
// never saw that checkout and still reports the branch it was opened with.
// The paths that rely on this pin run effectively single-connection —
// server-mode stores are pinned to MaxOpenConns=1 precisely because branch
// isolation is session-level (see iter_issues.go) — so the read is reliable
// in practice rather than by construction. The s.branch fallback does not
// close the gap either: it fires only when the query errors, not when it
// succeeds with another connection's answer.
func (s *DoltStore) pinStoreBranch(ctx context.Context, conn execer) error {
	var branch string
	if scanErr := s.db.QueryRowContext(ctx, "SELECT active_branch()").Scan(&branch); scanErr == nil {
		if branch != "" {
			if _, err := conn.ExecContext(ctx, "CALL DOLT_CHECKOUT(?)", branch); err != nil {
				return fmt.Errorf("checkout active branch %q: %w", branch, err)
			}
		}
	} else if s.branch != "" {
		// Fall back to the store's recorded branch rather than failing the
		// whole call outright.
		if _, err := conn.ExecContext(ctx, "CALL DOLT_CHECKOUT(?)", s.branch); err != nil {
			return fmt.Errorf("checkout fallback branch %q: %w", s.branch, err)
		}
	}
	return nil
}

// withReadTxLongTimeout is like withReadTx but runs fn against a dedicated
// one-shot connection with a 5-minute read timeout (see openLongTimeoutConn)
// instead of the shared pool's 10s ReadTimeout (see buildServerDSN). Use for
// read queries that are known to legitimately run long, e.g. dolt_history_*
// system-table scans on issues with many revisions — the pooled 10s client
// timeout otherwise surfaces as an intermittent MySQL i/o timeout / invalid

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the branch exists: run SELECT active_branch() and DOLT_BRANCH() in the database, or bd doctor.
  2. Recreate the missing branch or reconfigure the store's branch to an existing one.
  3. Restart the store/process to reset pooled connections if a session is wedged.
  4. Check whether another process is rewriting branches concurrently and serialize those operations.

Example fix

// before
s.branch = "work/foo" // branch later deleted by another process
// after
// ensure branch exists before opening the store
_, err := db.Exec("CALL DOLT_BRANCH(?, ?)", "work/foo", "main")
s.branch = "work/foo"
Defensive patterns

Strategy: fallback

Validate before calling

var branch string
if err := db.QueryRowContext(ctx, "SELECT active_branch()").Scan(&branch); err != nil || branch == "" {
	// branch unknown; verify DOLT_BRANCH() list before writing
}

Try / catch

if err := op(ctx); err != nil {
	if strings.Contains(err.Error(), "checkout active branch") {
		// recreate the branch or reopen the store pinned to an existing branch
	}
	return err
}

Prevention

When it happens

Trigger: Executing any statement on a pooled connection when DOLT_CHECKOUT of the active branch fails — the branch was deleted/renamed on the connection's view, the database was rebuilt without that branch, or the SQL session errored.

Common situations: Branch deleted or renamed by another process between operations; repo directory re-initialized losing the recorded branch; mismatch between the store's configured branch and the database's actual branches; corrupted connection after a server restart.

Related errors


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