gastownhall/beads · error
multiple .doltcfg directories detected
Error message
multiple .doltcfg directories detected
What it means
ErrMultipleDoltCfgDirs is returned by resolveCfgDir when both a parent-directory .doltcfg and a data-directory .doltcfg exist. This mirrors Dolt's own ErrMultipleDoltCfgDirs: guessing which config wins risks silently losing user or branch-control settings, so the launcher treats it as a hard Start() failure instead of picking one arbitrarily.
Source
Thrown at internal/doltserver/doltserver.go:1095
// (see SupportsArchiveLevelConfig). It lives alongside the other gitignored
// server state files in beadsDir, not inside the Dolt data directory.
const doltServerConfigFileName = "dolt-server-config.yaml"
func doltServerConfigPath(beadsDir string) string {
return filepath.Join(beadsDir, doltServerConfigFileName)
}
// doltCfgDirName mirrors commands.DefaultCfgDirName in the pinned dolt
// module (cmd/dolt/commands/sql.go) — the on-disk directory name Dolt looks
// in for privileges.db (users/passwords) and branch_control.db.
const doltCfgDirName = ".doltcfg"
// ErrMultipleDoltCfgDirs is returned by resolveCfgDir when both a parent
// and a data-directory .doltcfg exist. Mirrors Dolt's own ambiguous case
// (commands.ErrMultipleDoltCfgDirs in the pinned module) — guessing which
// one to use risks the same silent user/branch-control loss this function
// exists to prevent, so this is surfaced as a hard Start() failure instead.
var ErrMultipleDoltCfgDirs = errors.New("multiple .doltcfg directories detected")
// resolveCfgDir replicates Dolt's own flag-mode .doltcfg discovery
// (setupDoltConfig in cmd/dolt/commands/sqlserver/sqlserver.go, pinned
// module) for our generated --config YAML. setupDoltConfig returns
// immediately when --config is passed, so a deployment that previously ran
// this launcher in CLI-flag mode — where dolt auto-discovers a parent
// ../.doltcfg holding privileges.db/branch_control.db — would otherwise
// silently fall back to a fresh $data_dir/.doltcfg under --config mode:
// existing users and branch controls abandoned, new passwordless root
// (gastownhall/beads#4986).
//
// doltDir is the server's data directory (== process cwd, since neither
// --data-dir nor --doltcfg-dir are ever passed). Mirrors Dolt exactly:
// - parent ../.doltcfg (relative to doltDir) if it exists and is a dir
// - else doltDir/.doltcfg
// - ErrMultipleDoltCfgDirs if BOTH exist — ambiguous, matches Dolt's own
// ErrMultipleDoltCfgDirs case rather than guessing.
//View on GitHub (pinned to 71377f2769)
Solutions
- Delete the redundant .doltcfg from either the parent or the data directory (keep the one with the intended user/branch-control settings).
- Merge the desired settings into a single .doltcfg and remove the other before restarting.
- Run the launcher with a data directory whose ancestor chain contains no other .doltcfg (e.g. clean container workdir).
Example fix
// before $ ls /srv/beads/.doltcfg /srv/beads/data/.doltcfg # both exist -> Start() fails // after $ mv /srv/beads/data/.doltcfg/user.json /srv/beads/.doltcfg/user.json # merge, then: $ rm -rf /srv/beads/data/.doltcfg $ bd <start launcher> # resolves single /srv/beads/.doltcfg
Defensive patterns
Strategy: validation
Validate before calling
// before calling Start(), detect the ambiguity yourself
func hasMultipleDoltCfgDirs(dataDir string) (bool, error) {
abs, err := filepath.Abs(dataDir)
if err != nil {
return false, err
}
for dir := abs; ; dir = filepath.Dir(dir) {
hits := 0
for _, d := range []string{dir, filepath.Dir(dir)} {
if fi, err := os.Stat(filepath.Join(d, ".doltcfg")); err == nil && fi.IsDir() {
hits++
}
}
if hits > 1 {
return true, nil
}
if dir == filepath.Dir(dir) {
break
}
}
return false, nil
} Try / catch
if err := server.Start(ctx); err != nil {
if errors.Is(err, doltserver.ErrMultipleDoltCfgDirs) {
// inspect parent and data dirs, keep/merge one .doltcfg, then restart
}
return err
} Prevention
- Keep exactly one .doltcfg in the deployment: bake it into the data volume, not image ancestors like /.
- After migrating from dolt CLI-flag mode, audit the parent directory for a leftover .doltcfg.
- In containers, set the working directory to the data dir so dolt's auto-discovery cannot pick up an ancestor config.
When it happens
Trigger: Starting the external Dolt server launcher (Start() path through resolveCfgDir) when the working/parent directory and the configured data directory each contain a .doltcfg directory. Happens when a deployment previously ran dolt in CLI-flag mode from a parent directory that auto-discovered .doltcfg, and the data dir later gained its own .doltcfg.
Common situations: Repointing the launcher's data directory after previously running dolt sql-server directly from a parent checkout that already had .doltcfg; container images where one .doltcfg is baked at / and another is created in the data volume; moving repo roots without cleaning up the old config directory.
Related errors
- dolt directory is required
- dolt path is not executable
- ErrFSCKTimeout
- database %q not found on Dolt server at %s:%d
- not using Dolt backend (configured backend %q)
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ae58b64e00a90183.
Report an issue: GitHub.