fix: ApplyCLIAutoStart respects ServerModeExternal (mirror NewFromConfigWithOptions)#3473
Merged
maphew merged 2 commits intoApr 25, 2026
Conversation
…figWithOptions)
ApplyCLIAutoStart hardcoded ServerModeOwned when calling
resolveAutoStart, bypassing the external-mode check (priority 3
in resolveAutoStart's docstring) that prevents the "shadow
database bug": when a repo has metadata.json dolt_server_port
set (External mode) and the configured server is transiently
unreachable, bd was free to spawn a fallback embedded server
from .beads/dolt/.
The companion path NewFromConfigWithOptions correctly resolves
the actual server mode (open.go:104) and passes it to
resolveAutoStart, so external-mode suppression worked there.
The cmd/bd/main.go:889 path that routes through ApplyCLIAutoStart
silently lost the protection.
Real-world failure mode (factfiber.ai 2026-04-24): during a
silk/Dolt service cutover, a bd write hook in an external-mode
repo fell into ApplyCLIAutoStart's path, hit a transient connect
failure to the configured server, and spawned a shadow Dolt
sql-server on the same loopback port. The orphan ran for 18
hours intercepting bd commands from other shells and surfacing
"database not found" errors.
Fix: have ApplyCLIAutoStart call doltserver.ResolveServerMode
and pass the actual mode, mirroring the NewFromConfigWithOptions
shape.
The function's prior comment ("intentionally ignores metadata.json
explicit-port suppression so doctor and other CLI helper paths
behave the same way as cmd/bd/main.go on cold repo-local
standalone setups") is no longer load-bearing once respected:
for a cold standalone setup post-bd-init, the server is already
running, so no fallback auto-start is needed; if the user
explicitly stops the server, External mode's "you manage the
lifecycle" semantics correctly asks the user to run
'bd dolt start'.
Add TestApplyCLIAutoStart_RespectsExternalMode regression test:
metadata.json with dolt_server_port set + no config.yaml
dolt.auto-start → cfg.AutoStart must be false.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
maphew
approved these changes
Apr 25, 2026
maphew
left a comment
Collaborator
There was a problem hiding this comment.
Reviewed the contributor fix and pushed a small maintainer repair to align the stale doctor autostart test with the new external-mode behavior. Preserved the regression test and validated locally with targeted package tests plus make test; CI is green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
`ApplyCLIAutoStart` (in `internal/storage/dolt/open.go`) hardcoded
`ServerModeOwned` when calling `resolveAutoStart`, bypassing the
external-mode check that `resolveAutoStart`'s docstring lists as
priority 3 — the protection against the shadow database bug:
when a repo has `metadata.json dolt_server_port` set (External
mode) and the configured server is transiently unreachable, bd
was free to spawn a fallback embedded server from `.beads/dolt/`.
The companion path `NewFromConfigWithOptions` correctly resolves
the actual server mode (open.go:104) and passes it to
`resolveAutoStart`, so external-mode suppression worked there.
The `cmd/bd/main.go:889` path that routes through
`ApplyCLIAutoStart` silently lost the protection.
Real-world failure mode
Hit at factfiber.ai 2026-04-24 during a service cutover that
briefly took the team's central Dolt server offline. A bd
write hook fired in an external-mode repo, hit a transient
connect-failure to the configured server, and spawned a shadow
`dolt sql-server` on the same loopback port. The orphan
ran for 18 hours, intercepting bd commands from other shells
and surfacing "database not found" errors against an empty
fallback chunkstore. Investigation in
this team's notes
traced it to `ApplyCLIAutoStart`'s hardcoded `ServerModeOwned`.
Patch
```diff
func ApplyCLIAutoStart(beadsDir string, cfg *Config) {
autoStartCfg := config.GetString("dolt.auto-start")
if autoStartCfg == "" {
autoStartCfg = config.GetStringFromDir(beadsDir, "dolt.auto-start")
}
}
```
Plus an updated doc comment explaining why the prior rationale
("so doctor and other CLI helper paths behave the same way as
cmd/bd/main.go on cold repo-local standalone setups") is no
longer load-bearing once respected: a cold standalone post-bd-init
already has its server running, so no fallback auto-start is
needed; if the user explicitly stops the server, External mode's
"you manage the lifecycle" semantics asks the user to run
`bd dolt start`.
Test plan
in `internal/storage/dolt/open_test.go` — metadata.json with
`dolt_server_port` set + no config.yaml `dolt.auto-start` →
`cfg.AutoStart` must be false. Pre-fix this returned true.
passes (with `BEADS_DOLT_SERVER_HOST` cleared from env —
pre-existing test isolation requirement).
Notes
in fix: consult config.yaml for dolt.host in GetDoltServerHost (mirror GH#2073) #3471 (mirroring of GH#2073's port fix to host).
`internal/doltserver` for the `ServerMode` re-exports, so no
new dependency.