JuliusBrussee/caveman · error

native runtime chmod socket: %w

Error message

native runtime chmod socket: %w

What it means

Returned when os.Chmod(path, 0o600) fails on the freshly created Unix socket. The listener already bound successfully; this step locks the socket to the owning user. It fails when the socket file disappears between listen and chmod or the kernel/FS rejects mode changes on sockets.

Source

Thrown at proxy/internal/nativeruntime/server_unix.go:61

		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()
		_ = listener.Close()
	}()
	for {
		conn, err := listener.Accept()
		if err != nil {
			if ctx.Err() != nil {
				return nil
			}
			return fmt.Errorf("native runtime accept: %w", err)
		}
		go serveConn(ctx, conn, runtime)
	}
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Ensure only one instance serves a given home directory at a time (single-flight lock or distinct homes)
  2. Move the socket onto a normal local filesystem (not NFS/FUSE) by relocating home
  3. If a cleanup daemon is deleting the socket, exclude the socket path from it
  4. Retry Serve after confirming the socket path is stable

Example fix

// before: two goroutines/processes sharing one home — loser's stale-cleanup unlinks winner's socket
err := nativeruntime.Serve(ctx, sharedHome, rt)

// after: serialize startup per home (e.g. a lock file) so only one server owns the socket path
if err := acquireHomeLock(sharedHome); err != nil { return err }
err := nativeruntime.Serve(ctx, sharedHome, rt)
Defensive patterns

Strategy: validation

Validate before calling

// Ensure exclusive ownership of the socket path before Serve
if conn, err := net.Dial("unix", sockPath); err == nil {
    _ = conn.Close()
    return errors.New("socket in use; another instance is running")
}

Try / catch

if err := nativeruntime.Serve(ctx, home, rt); err != nil {
    if errors.Is(err, syscall.ENOENT) && strings.Contains(err.Error(), "chmod socket") {
        // socket vanished between listen and chmod — retry once after a beat
        time.Sleep(100 * time.Millisecond)
        err = nativeruntime.Serve(ctx, home, rt)
    }
}

Prevention

When it happens

Trigger: Calling Serve on Unix where another process (a concurrent instance or an aggressive cleaner) unlinks the socket file in the window between net.Listen and os.Chmod, or the socket lives on a filesystem that refuses chmod on socket inodes (some FUSE/network mounts).

Common situations: Two caveman instances racing on the same home — the loser's stale-socket cleanup removed the winner's new socket; tmp-reaper daemons deleting files in the home directory; home on NFS or a container volume with restricted ioctl support.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/7de5d306c627fd18. Report an issue: GitHub.