gastownhall/beads · error

server: NewDoltServer: failed to determine absolute path of

Error message

server: NewDoltServer: failed to determine absolute path of rootDir

What it means

NewDoltServer resolves rootDir (the Dolt data directory) to an absolute path with filepath.Abs so the server identity hash and child process configuration are stable regardless of cwd. This fails only when the process's current working directory cannot be determined (deleted cwd or getwd failure) and rootDir was passed as a relative path.

Source

Thrown at internal/storage/dbproxy/server/doltserver.go:79

var _ DatabaseServer = (*DoltServer)(nil)

func NewDoltServer(doltBinExec, rootDir, configPath, logFilePath string, keepAlivePeriod time.Duration, database string) (*DoltServer, error) {
	if doltBinExec == "" {
		return nil, errors.New("server: NewDoltServer: doltBinExec is required")
	}
	if rootDir == "" {
		return nil, errors.New("server: NewDoltServer: rootDir is required")
	}
	if configPath == "" {
		return nil, errors.New("server: NewDoltServer: configPath is required")
	}
	absDoltBinExec, err := filepath.Abs(doltBinExec)
	if err != nil {
		return nil, errors.New("server: NewDoltServer: failed to determine absolute path of doltBinExec")
	}
	absRootDir, err := filepath.Abs(rootDir)
	if err != nil {
		return nil, errors.New("server: NewDoltServer: failed to determine absolute path of rootDir")
	}
	absConfigPath, err := filepath.Abs(configPath)
	if err != nil {
		return nil, errors.New("server: NewDoltServer: failed to determine absolute path of configPath")
	}
	cfg, err := servercfg.YamlConfigFromFile(filesys.LocalFS, configPath)
	if err != nil {
		return nil, fmt.Errorf("server: NewDoltServer: parse config %q: %w", configPath, err)
	}
	var logFile *os.File
	if logFilePath != "" {
		absLogFilePath, err := filepath.Abs(logFilePath)
		if err != nil {
			return nil, errors.New("server: NewDoltServer: failed to determine absolute path of logFilePath")
		}
		logFile, err = os.OpenFile(absLogFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o600) //nolint:gosec // logFilePath is caller-derived, not user-request input
		if err != nil {
			return nil, fmt.Errorf("server: NewDoltServer: open log %q: %w", logFilePath, err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Pass an absolute rootDir; resolve it once at startup while the cwd is still valid and reuse it
  2. Verify the process cwd exists (readlink /proc/<pid>/cwd) — if deleted, restart the process
  3. Recreate the deleted working directory or restart the application from an existing directory

Example fix

// before
srv, err := server.NewDoltServer(bin, ".beads", cfgPath, logPath, 0, db)
// after
absRoot, err := filepath.Abs(".beads") // resolve early, before any chdir/removal
if err != nil { return err }
srv, err := server.NewDoltServer(bin, absRoot, cfgPath, logPath, 0, db)
Defensive patterns

Strategy: validation

Validate before calling

root, err := filepath.Abs(rootDir)
if err != nil { return fmt.Errorf("cannot resolve data dir (cwd invalid?): %w", err) }
if st, err := os.Stat(root); err != nil || !st.IsDir() { return fmt.Errorf("data dir %s missing", root) }

Prevention

When it happens

Trigger: Calling NewDoltServer with a relative rootDir (e.g. ".beads") while os.Getwd() fails because the working directory was deleted or is inaccessible. An absolute rootDir bypasses this code path entirely.

Common situations: Daemon started in a directory later removed by tmp-cleaners or CI workspace cleanup; running inside a container whose WORKDIR was deleted; getwd failures on systems with permission issues on the cwd.

Related errors


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