JuliusBrussee/caveman · error
native runtime: socket already active
Error message
native runtime: socket already active
What it means
The unix-socket Serve function probes an existing socket path with a 50ms dial before listening. If the dial succeeds, another live runtime owns that socket and Serve refuses to start rather than stealing it. Only when the dial fails is the stale socket file removed and the path reused.
Source
Thrown at proxy/internal/nativeruntime/server_unix.go:46
// ServeUnix exposes one-request-per-connection JSON over a user-only Unix
// socket. Runtime errors close or fail-open the individual call; they never stop
// the coding agent or the provider proxy.
func ServeUnix(ctx context.Context, path string, runtime *Runtime) error {
if runtime == nil || runtime.store == nil {
return errors.New("native runtime: store is required")
}
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
return fmt.Errorf("native runtime mkdir: %w", err)
}
if err := os.Chmod(filepath.Dir(path), 0o700); err != nil {
return fmt.Errorf("native runtime chmod dir: %w", err)
}
if _, err := os.Stat(path); err == nil {
conn, dialErr := net.DialTimeout("unix", path, 50*time.Millisecond)
if dialErr == nil {
_ = conn.Close()
return errors.New("native runtime: socket already active")
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("native runtime remove stale socket: %w", err)
}
} else if !os.IsNotExist(err) {
return fmt.Errorf("native runtime inspect socket: %w", err)
}
listener, err := net.Listen("unix", path)
if err != nil {
return fmt.Errorf("native runtime listen: %w", err)
}
defer listener.Close()
defer os.Remove(path)
if err := os.Chmod(path, 0o600); err != nil {
return fmt.Errorf("native runtime chmod socket: %w", err)
}
go func() {
<-ctx.Done()View on GitHub (pinned to 27d5a3981a)
Solutions
- Find and stop the existing instance (check the run-state file for its PID) before starting a new one
- Use a different home directory for the second instance if concurrent runtimes are intended
- If truly stale, ensure the old process is killed; the server will then remove the dead socket itself
Example fix
# before $ caveman-proxy serve & # second instance, same home -> socket already active # after $ pkill -f caveman-proxy || kill $(cat ~/.caveman/runstate/port-*/pid) $ caveman-proxy serve &
Defensive patterns
Strategy: validation
Validate before calling
conn, err := net.DialTimeout("unix", socketPath, 50*time.Millisecond)
if err == nil {
conn.Close()
return errors.New("another runtime is already serving this home")
} Try / catch
if err := nativeruntime.Serve(ctx, home, rt); err != nil {
if strings.Contains(err.Error(), "socket already active") {
// stop the existing instance via its run-state PID, then restart
}
} Prevention
- Use the run-state file to find and stop the previous instance before restarts
- Give concurrent instances separate home directories
- Ensure supervisors wait for process exit before restarting
When it happens
Trigger: Starting a second runtime instance with the same home directory while the first is still serving; an orchestrator/supervisor restarting the service before the old process fully exited; running two proxy commands concurrently against the same home.
Common situations: Development running the daemon twice; systemd/docker restart races where the old process lingers; forking a child that inherits and re-serves the same home path.
Related errors
- native runtime mkdir: %w
- native runtime inspect socket: %w
- native runtime listen: %w
- native runtime: invalid decision id
- native runtime: invalid decision record
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/f4de5c3222262623.
Report an issue: GitHub.