gastownhall/beads · error
opening log file: %w
Error message
opening log file: %w
What it means
Start() opens (creating if needed) the dolt server log file at logPath(beadsDir) with mode 0600 before launching the child process. If os.OpenFile fails, the error is wrapped as 'opening log file'. The server refuses to start without a log sink because diagnostics for later failures (e.g. GH#3290) depend on it.
Source
Thrown at internal/doltserver/doltserver.go:1347
// only intervene between runs. See logrotate.go for the caveat discussion.
maybeRotateLog(beadsDir)
// Resolve .doltcfg once, before the port retry loop — it does not
// depend on the port, and an ambiguous both-exist result must fail
// Start() outright rather than retry into a fresh unintended
// $data_dir/.doltcfg (see resolveCfgDir).
var cfgDir string
if useArchiveLevelConfig {
cfgDir, err = resolveCfgDir(doltDir)
if err != nil {
return nil, fmt.Errorf("resolving .doltcfg directory: %w", err)
}
}
// Open log file
logFile, err := os.OpenFile(logPath(beadsDir), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) //nolint:gosec // G304: logPath derives from user-configured beadsDir
if err != nil {
return nil, fmt.Errorf("opening log file: %w", err)
}
// Resolve the port to use. Explicit ports (env/config) go through
// reclaimPort for conflict detection. Port 0 means ephemeral — allocate
// a fresh port from the OS with retry for TOCTOU races.
actualPort = cfg.Port
explicitPort := actualPort > 0
if explicitPort {
// Explicit port: check for conflicts and adopt existing servers.
adoptPID, reclaimErr := reclaimPort(cfg.Host, actualPort, beadsDir)
if reclaimErr != nil {
_ = logFile.Close()
return nil, fmt.Errorf("cannot start dolt server on port %d: %w", actualPort, reclaimErr)
}
if adoptPID > 0 {
_ = logFile.Close()
_ = os.WriteFile(pidPath(beadsDir), []byte(strconv.Itoa(adoptPID)), 0600)View on GitHub (pinned to 71377f2769)
Solutions
- Check permissions/ownership of the beads data directory and fix with chown/chmod.
- Verify no file/directory with the log file's name blocks creation.
- Free disk space or inodes if the volume is full.
- Check ulimit -n (open file limit) if EMFILE is reported and close leaked descriptors.
Example fix
// before ls -l ~/.beads/logs // after chmod u+w ~/.beads ~/.beads/logs # or clear space: df -h ~/.beads
Defensive patterns
Strategy: validation
Validate before calling
const logFile = path.join(dataDir, 'dolt.log');
try { await fs.appendFile(logFile, ''); } // probes create+write
catch { throw new Error(`Cannot write dolt log at ${logFile}; fix permissions/disk`); } Type guard
null
Try / catch
try {
await bdStart();
} catch (e) {
if (/opening log file/.test(e.message)) {
// inspect errno: EACCES -> permissions, ENOSPC -> disk, EMFILE -> fd limit
}
throw e;
} Prevention
- Keep the beads dir writable by the running user.
- Watch disk space/inode usage.
- Raise ulimit -n for long-lived daemons.
- Don't create files/dirs that collide with the log path.
When it happens
Trigger: os.OpenFile(logPath(beadsDir), O_CREATE|O_APPEND|O_WRONLY, 0600) fails: unwritable directory, path is a directory, or too many open files.
Common situations: Beads dir permissions wrong after a user/uid change; disk full; logPath colliding with a directory of the same name; EMFILE under heavy fd usage in long-lived processes.
Related errors
- open proxy log %q: %w
- multiple .doltcfg directories detected
- server: NewDoltServer: failed to determine absolute path of
- resolving .doltcfg directory: %w
- resolving managed sql-server config path: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b752028699fe50c5.
Report an issue: GitHub.