JuliusBrussee/caveman · error

native runtime listen: %w

Error message

native runtime listen: %w

What it means

Returned when net.Listen("unix", path) fails while the native runtime is trying to bind its local Unix socket. The server had just cleaned (or verified absent) a stale socket, so this usually means the path is unwritable, too long, or another process created a socket between the stale check and the listen.

Source

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

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

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Check that the socket's parent directory (home/run or equivalent) exists and is writable by the current user
  2. Ensure no second caveman process is already serving the same home (lsof on the socket path); stop it or use a different home
  3. Shorten the socket path — put home closer to the filesystem root or raise the home directory if the path exceeds the OS sun_path limit
  4. If the directory is on a filesystem that does not support Unix sockets (some network mounts), move home to a local filesystem

Example fix

// before: home deep under a long path, listen fails with 'invalid argument'
home := "/very/long/nested/path/that/exceeds/unix/socket/limits/.caveman"
err := nativeruntime.Serve(ctx, home, rt)

// after: keep the socket path short
home := "/home/user/.caveman"
err := nativeruntime.Serve(ctx, home, rt)
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(sockPath)
if info, err := os.Stat(dir); err != nil || !info.IsDir() {
    return fmt.Errorf("socket directory %s missing", dir)
}
if len(sockPath) >= 104 { // typical sun_path limit
    return fmt.Errorf("socket path too long (%d bytes)", len(sockPath))
}

Try / catch

if err := nativeruntime.Serve(ctx, home, rt); err != nil {
    if strings.Contains(err.Error(), "native runtime listen") {
        // inspect %w chain: errors.Is(err, os.ErrPermission) vs syscall.EADDRINUSE
    }
    return err
}

Prevention

When it happens

Trigger: Calling nativeruntime.Serve on Unix when (a) the parent directory of the socket path does not exist or lacks write permission, (b) the socket path exceeds the ~104-108 byte sun_path limit, or (c) a second caveman process started concurrently and won the listen race after the stale-socket probe.

Common situations: HOME points to a read-only or non-existent directory; a leftover-but-active listener from an earlier run (socket-active check passed only for a dead peer); running two instances with the same home; deeply nested home paths blowing past the Unix socket path-length limit.

Related errors


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