{"record":{"id":"c33f7228e4372bf9","repo":"gastownhall/beads","slug":"errcircuitopen","errorCode":"ErrCircuitOpen","errorMessage":"dolt circuit breaker is open: server appears down, failing fast (cooldown %s)","messagePattern":"dolt circuit breaker is open: server appears down, failing fast \\(cooldown (.+?)\\)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/storage/dolt/circuit.go","lineNumber":91,"sourceCode":"}\n\n// circuitBreaker manages the circuit breaker for a specific Dolt server\n// host:port:database combination. Using per-database granularity prevents\n// degradation in one project from tripping the breaker for all worktrees\n// sharing the same server (GH#3140).\n//\n// It uses a file under os.TempDir() for cross-process state sharing and an in-process\n// mutex for thread safety within a single process.\ntype circuitBreaker struct {\n\thost     string\n\tport     int\n\tdatabase string\n\tfilePath string\n\tmu       sync.Mutex\n}\n\n// ErrCircuitOpen is returned when the circuit breaker is open and rejecting requests.\nvar ErrCircuitOpen = fmt.Errorf(\"dolt circuit breaker is open: server appears down, failing fast (cooldown %s)\", circuitCooldown)\n\n// maybeNewCircuitBreaker returns a file-backed circuit breaker only for a\n// concrete port. Port 0 means \"not yet resolved\" during standalone auto-start,\n// and sharing breaker state on port 0 poisons every fresh init on the machine.\n// The database parameter scopes the breaker to a specific project so that\n// degradation in one database doesn't trip the breaker for others (GH#3140).\nfunc maybeNewCircuitBreaker(host string, port int, database string) *circuitBreaker {\n\tif port <= 0 {\n\t\treturn nil\n\t}\n\treturn newCircuitBreaker(host, port, database)\n}\n\n// circuitBreakerDir returns the dedicated directory for circuit breaker state\n// files. Using a subdirectory avoids scanning all of the temp root (which may\n// contain millions of entries) when cleaning up stale breaker files on\n// startup. Derived from os.TempDir() so it is correct on every platform:\n// hardcoding \"/tmp\" resolved to C:\\tmp on Windows, silently accumulating","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/circuit.go#L73-L109","documentation":"ErrCircuitOpen is a sentinel error from the file-backed Dolt circuit breaker. After repeated failures (notably indeterminate commit failures) the breaker opens and fails fast for a cooldown period (circuitCooldown) instead of hammering an unreachable server. It signals the Dolt SQL server is believed down; the breaker is scoped per database and only active for a concrete resolved port.","triggerScenarios":"Any Dolt-backed write/read (update, claim, delete, wisp dependency ops, WithRetryTx) while the breaker is open after the failure threshold tripped — e.g. consecutive indeterminate commit errors or connection failures to the dolt sql-server.","commonSituations":"dolt sql-server crashed or was stopped mid-session; wrong port after auto-start; network partition to a remote Dolt server; a prior indeterminate commit sequence tripped the breaker and the cooldown has not elapsed.","solutions":["Verify the Dolt server is running and reachable (e.g. `dolt sql-server` status / `bd doctor`) and restart it if needed","Wait for the cooldown period to elapse — the breaker will half-open and allow retry attempts automatically","Check you are not sharing a stale breaker file from another database/port; the breaker is per-database and per-port, so a resolved concrete port is required","Fix the underlying connectivity issue (port config, process down) — the breaker only resets behavior, not the root cause"],"exampleFix":"// before\n// writes fail fast with ErrCircuitOpen while server is down\n// after\n# restart the server, then wait out the cooldown before retrying\ndolt sql-server &\n# retry the bd command after cooldown","handlingStrategy":"retry","validationCode":"// check server reachability before issuing writes\n// e.g. run `bd doctor` or a cheap query against dolt sql-server;\n// if the breaker file marks the port open, back off instead of writing","typeGuard":null,"tryCatchPattern":"if err := store.UpdateIssue(ctx, id, opts); err != nil {\n    if errors.Is(err, dolt.ErrCircuitOpen) {\n        // fail fast; wait out the cooldown, verify server health, then retry\n        time.Sleep(cooldown); if serverHealthy() { retryWrite() }\n    }\n}","preventionTips":["Monitor dolt sql-server health and restart it proactively","Fix port/auto-start configuration so the breaker binds a concrete port per database","Back off and retry after cooldown rather than hammering a down server","Watch for indeterminate-commit failures, which trip the breaker early"],"tags":["dolt","circuit-breaker","server-down","fail-fast"],"backgroundTag":"circuit-breaker-open","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}