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
- Check for and stop any other process serving the same home (Get-ChildItem \\.\pipe\ | findstr or Process Explorer handle search)
- Restart the previous instance's orphaned children that still hold pipe handles, or reboot to clear stale handles
- Shorten home so the derived pipe name stays well under the 256-character pipe-name limit
- 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
- One instance per home on Windows; pipes are not auto-cleaned like stale Unix sockets
- Keep the derived pipe name short (pipe namespace limit is 256 chars)
- Add AV/EDR exclusions for the pipe if security software interferes
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
- native runtime current user SID: unavailable
- native runtime current user SID: %w
- native runtime named-pipe accept: %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/5cda62458b8773df.
Report an issue: GitHub.