JuliusBrussee/caveman · error
native runtime named-pipe accept: %w
Error message
native runtime named-pipe accept: %w
What it means
Returned when listener.Accept() fails on the Windows named pipe and neither the context is cancelled nor the error is net.ErrClosed. This is an unexpected accept failure on the pipe listener — typically a broken pipe instance or OS-level error, since intentional shutdown is filtered by the ctx.Err()/ErrClosed checks.
Source
Thrown at proxy/internal/nativeruntime/server_windows.go:68
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
- Update go-winio to the latest version — accept/retry logic around broken pipe instances has seen fixes
- Exclude the caveman pipe from AV/EDR scanning and prevent external tools from closing its handles
- Add a resilience wrapper: on error, close the listener and re-enter Serve while ctx is alive
- Check Windows Event Log for pipe/FS errors if it recurs
Example fix
// before: any non-shutdown accept error terminates Serve
return fmt.Errorf("native runtime named-pipe accept: %w", err)
// after: supervise the server loop so a transient accept failure restarts the pipe
for {
if err := nativeruntime.Serve(ctx, home, rt); err != nil && ctx.Err() == nil {
log.Warn("native runtime exited, restarting", "error", err)
time.Sleep(time.Second)
continue
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
null
Try / catch
for {
err := nativeruntime.Serve(ctx, home, rt)
if err == nil || ctx.Err() != nil { return err }
var ne net.Error
if errors.As(err, &ne) || strings.Contains(err.Error(), "named-pipe accept") {
log.Warn("pipe accept failed; recreating listener", "error", err)
select { case <-time.After(time.Second): case <-ctx.Done(): return ctx.Err() }
continue
}
return err
} Prevention
- Supervise the Serve loop so transient pipe errors recover without operator action
- Update go-winio regularly; accept-path robustness improves between releases
- Prevent external tools from closing pipe handles
When it happens
Trigger: Long-running Serve on Windows where the underlying named pipe instance is destroyed by an external handle close, or a Win32 accept error (pipe disconnected in an unrecoverable state) occurs while ctx is still live.
Common situations: Tooling (Process Explorer, debuggers) or AV software closing pipe handles; a go-winio version mismatch with the installed Windows version; the process running under a context that loses the pipe namespace after a session change (fast user switching, RDP disconnect).
Related errors
- native runtime named-pipe listen: %w
- native runtime current user SID: unavailable
- native runtime accept: %w
- native runtime current user SID: %w
- cannot safely launch Windows command shim: ${executable}
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/7611c89d436bd3ac.
Report an issue: GitHub.