{"record":{"id":"8610021f30c101ee","repo":"gastownhall/beads","slug":"checkout-active-branch-q-w","errorCode":null,"errorMessage":"checkout active branch %q: %w","messagePattern":"checkout active branch %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/store.go","lineNumber":1071,"sourceCode":"// pool behind s.db is effectively single-connection. Checkout() leases one\n// connection from that pool (s.db.Conn), runs DOLT_CHECKOUT on it and returns\n// it — the branch stays with that physical connection, because checkout is\n// per-connection session state. The pool defaults to defaultMaxOpenConns (10,\n// overridable by BEADS_DOLT_MAX_CONNS or dolt.max-conns), so on a genuinely\n// multi-connection pool this read may be served by a sibling connection that\n// never saw that checkout and still reports the branch it was opened with.\n// The paths that rely on this pin run effectively single-connection —\n// server-mode stores are pinned to MaxOpenConns=1 precisely because branch\n// isolation is session-level (see iter_issues.go) — so the read is reliable\n// in practice rather than by construction. The s.branch fallback does not\n// close the gap either: it fires only when the query errors, not when it\n// succeeds with another connection's answer.\nfunc (s *DoltStore) pinStoreBranch(ctx context.Context, conn execer) error {\n\tvar branch string\n\tif scanErr := s.db.QueryRowContext(ctx, \"SELECT active_branch()\").Scan(&branch); scanErr == nil {\n\t\tif branch != \"\" {\n\t\t\tif _, err := conn.ExecContext(ctx, \"CALL DOLT_CHECKOUT(?)\", branch); err != nil {\n\t\t\t\treturn fmt.Errorf(\"checkout active branch %q: %w\", branch, err)\n\t\t\t}\n\t\t}\n\t} else if s.branch != \"\" {\n\t\t// Fall back to the store's recorded branch rather than failing the\n\t\t// whole call outright.\n\t\tif _, err := conn.ExecContext(ctx, \"CALL DOLT_CHECKOUT(?)\", s.branch); err != nil {\n\t\t\treturn fmt.Errorf(\"checkout fallback branch %q: %w\", s.branch, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// withReadTxLongTimeout is like withReadTx but runs fn against a dedicated\n// one-shot connection with a 5-minute read timeout (see openLongTimeoutConn)\n// instead of the shared pool's 10s ReadTimeout (see buildServerDSN). Use for\n// read queries that are known to legitimately run long, e.g. dolt_history_*\n// system-table scans on issues with many revisions — the pooled 10s client\n// timeout otherwise surfaces as an intermittent MySQL i/o timeout / invalid","sourceCodeStart":1053,"sourceCodeEnd":1089,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/store.go#L1053-L1089","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the branch exists: run SELECT active_branch() and DOLT_BRANCH() in the database, or bd doctor.","Recreate the missing branch or reconfigure the store's branch to an existing one.","Restart the store/process to reset pooled connections if a session is wedged.","Check whether another process is rewriting branches concurrently and serialize those operations."],"exampleFix":"// before\ns.branch = \"work/foo\" // branch later deleted by another process\n// after\n// ensure branch exists before opening the store\n_, err := db.Exec(\"CALL DOLT_BRANCH(?, ?)\", \"work/foo\", \"main\")\ns.branch = \"work/foo\"","handlingStrategy":"fallback","validationCode":"var branch string\nif err := db.QueryRowContext(ctx, \"SELECT active_branch()\").Scan(&branch); err != nil || branch == \"\" {\n\t// branch unknown; verify DOLT_BRANCH() list before writing\n}","typeGuard":null,"tryCatchPattern":"if err := op(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"checkout active branch\") {\n\t\t// recreate the branch or reopen the store pinned to an existing branch\n\t}\n\treturn err\n}","preventionTips":["Don't delete or rename the Dolt branch while a bd process is running.","Keep the store's configured branch in sync with the repo's actual branches.","Reopen the store after external branch surgery to reset pooled connections.","Run bd doctor to verify branch/database state after rebuilds or migrations."],"tags":["dolt","branching","database","connection-pool"],"backgroundTag":"dolt-branch-checkout-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}