gastownhall/beads · error

writing port file: %w

Error message

writing port file: %w

What it means

This error is returned by doltserver.Start after the dolt sql-server process was successfully spawned, but writing the port file (<beadsDir>/dolt-server.port) to disk failed. Because the port file is how other bd processes discover which port the server listens on, a failure here leaves the server useless, so Start kills the fresh process and removes the just-written PID file before wrapping the underlying os.WriteFile error with %w.

Source

Thrown at internal/doltserver/doltserver.go:1492

			}
			return nil, fmt.Errorf("failed to start dolt server after %d attempts: %w\nCheck logs: %s",
				attempts, lastErr, logPath(beadsDir))
		}
	}

	// Write PID and port files
	if err := os.WriteFile(pidPath(beadsDir), []byte(strconv.Itoa(pid)), 0600); err != nil {
		if proc, findErr := os.FindProcess(pid); findErr == nil {
			_ = proc.Kill()
		}
		return nil, fmt.Errorf("writing PID file: %w", err)
	}
	if err := writePortFile(beadsDir, actualPort); err != nil {
		if proc, findErr := os.FindProcess(pid); findErr == nil {
			_ = proc.Kill()
		}
		_ = os.Remove(pidPath(beadsDir))
		return nil, fmt.Errorf("writing port file: %w", err)
	}

	// Wait for server to accept connections
	if err := waitForReady(cfg.Host, actualPort, readyTimeout()); err != nil {
		if proc, findErr := os.FindProcess(pid); findErr == nil {
			_ = proc.Kill()
		}
		_ = os.Remove(pidPath(beadsDir))
		_ = os.Remove(portPath(beadsDir))
		if hasJournalCorruption, logErr := logHasCorruptJournalError(logPath(beadsDir)); logErr == nil && hasJournalCorruption {
			return nil, fmt.Errorf("server started (PID %d) but not accepting connections on port %d: %w\n\n%s",
				pid, actualPort, err, corruptJournalRecoveryHint(beadsDir))
		}
		return nil, fmt.Errorf("server started (PID %d) but not accepting connections on port %d: %w\nCheck logs: %s",
			pid, actualPort, err, logPath(beadsDir))
	}

	return &State{

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check permissions and writability of the beads directory (ls -ld .beads) and ensure the current user can create files there
  2. Free disk space and check inode/quota limits (df -h, df -i)
  3. Remove any stale or immutable dolt-server.port file (rm -f .beads/dolt-server.port; chattr -i if needed)
  4. If the directory is intentionally read-only, run bd against a writable beads dir or relocate BEADS_DIR
  5. Retry bd; if persistent, inspect the wrapped error (%w) for the exact errno

Example fix

// before: start fails, server killed
// $ bd doctor
//   error: writing port file: open /repo/.beads/dolt-server.port: read-only file system
// after: make the beads dir writable (or mount it writable)
// $ mount -o remount,rw /repo
// $ chmod u+w /repo/.beads
Defensive patterns

Strategy: validation

Validate before calling

// Before starting, ensure the beads dir exists and is writable
info, err := os.Stat(beadsDir)
if err != nil || !info.IsDir() {
    return fmt.Errorf("beads dir %s missing", beadsDir)
}
probe, perr := os.CreateTemp(beadsDir, ".write-probe*")
if perr != nil {
    return fmt.Errorf("beads dir not writable: %w", perr)
}
probe.Close(); os.Remove(probe.Name())

Prevention

When it happens

Trigger: writePortFile(beadsDir, actualPort) returns an error right after a successful server spawn — typically because the beads directory is read-only, was deleted mid-start, disk is full, an immutable/permission-locked file exists at the port path, or an OS-level I/O error occurs during os.WriteFile.

Common situations: Running bd in a container or CI workspace with a read-only or tmpfs-mounted beads dir; hitting a full disk after long unattended runs; the .beads directory being removed or permission-changed by another process while bd was starting; filesystem quota exhaustion; antivirus/EDR blocking writes to dot-directories.

Related errors


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