JuliusBrussee/caveman · error

native runtime named-pipe listen: %w

Error message

native runtime named-pipe listen: %w

What it means

Returned when winio.ListenPipe fails to create the Windows named pipe for the native runtime. This wraps CreateNamedPipe errors: the pipe name is already in use, the path is invalid, or the process lacks rights to create an object in that namespace.

Source

Thrown at proxy/internal/nativeruntime/server_windows.go:55

func Serve(ctx context.Context, home string, runtime *Runtime) error {
	if runtime == nil || runtime.store == nil {
		return errors.New("native runtime: store is required")
	}
	user, err := windows.GetCurrentProcessToken().GetTokenUser()
	if err != nil {
		return fmt.Errorf("native runtime current user SID: %w", err)
	}
	if user == nil || user.User.Sid == nil {
		return errors.New("native runtime current user SID: unavailable")
	}
	sddl := "D:P(A;;GA;;;" + user.User.Sid.String() + ")"
	listener, err := winio.ListenPipe(SocketPath(home), &winio.PipeConfig{
		SecurityDescriptor: sddl,
		InputBufferSize:    maxRequestBytes,
		OutputBufferSize:   maxRequestBytes,
	})
	if err != nil {
		return fmt.Errorf("native runtime named-pipe listen: %w", err)
	}
	defer listener.Close()
	go func() {
		<-ctx.Done()
		_ = listener.Close()
	}()
	for {
		conn, err := listener.Accept()
		if err != nil {
			if ctx.Err() != nil || errors.Is(err, net.ErrClosed) {
				return nil
			}
			return fmt.Errorf("native runtime named-pipe accept: %w", err)
		}
		go serveConn(ctx, conn, runtime)
	}
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Check for and stop any other process serving the same home (Get-ChildItem \\.\pipe\ | findstr or Process Explorer handle search)
  2. Restart the previous instance's orphaned children that still hold pipe handles, or reboot to clear stale handles
  3. Shorten home so the derived pipe name stays well under the 256-character pipe-name limit
  4. Temporarily disable/reconfigure AV interference if it is blocking pipe creation

Example fix

// before: second instance while first still runs
err := nativeruntime.Serve(ctx, sharedHome, rt)

// after: single instance per home; check the pipe first
if _, err := winio.DialPipeContext(ctx, pipeName); err == nil {
    return errors.New("native runtime: pipe already active")
}
err := nativeruntime.Serve(ctx, sharedHome, rt)
Defensive patterns

Strategy: validation

Validate before calling

// Before Serve on Windows, verify the pipe is free and the name is legal
name := nativeruntime.SocketPath(home)
if len(name) > 200 { return fmt.Errorf("pipe name too long") }
if _, err := winio.DialPipeContext(ctx, name); err == nil {
    return errors.New("pipe already in use")
}

Try / catch

if err := nativeruntime.Serve(ctx, home, rt); err != nil {
    if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, os.ErrNotExist) {
        // pipe namespace conflict or invalid name — check for another instance
    }
}

Prevention

When it happens

Trigger: Calling Serve on Windows when another caveman instance already listens on the same pipe name (winio pipes are exclusive in FILE_FLAG_FIRST_PIPE_INSTANCE terms), or the pipe path (derived from home) contains characters invalid in the \\.\pipe\ namespace.

Common situations: Two instances sharing one home directory; a crashed instance whose pipe handle is still held by a child process; pipe names longer than 256 chars from a deep home path; antivirus/security software holding or blocking pipe creation.

Related errors


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