netbirdio/netbird · error
%s: %w
Error message
%s: %w
What it means
On Windows, listenNamedPipe tried every candidate pipe path (protected name first, then the plain name) and each winio.ListenPipe call failed; errors.Join merges one error per path. The protected name needs administrator/LocalSystem, and failure of both names means the daemon could not serve on either.
Source
Thrown at client/cmd/service_pipe_windows.go:34
// listenNamedPipe creates the daemon control pipe and reports the path it ended
// up on. The security descriptor lets any local caller connect, as a Unix socket
// at 0666 does, and the privileged operations are authorized separately from the
// caller's token.
//
// The protected name comes first so that an unprivileged process cannot take the
// name before the service does. Creating it requires being an administrator or
// LocalSystem, so a daemon an ordinary user runs themselves, as in netstack mode,
// falls back to the plain name; clients try both and check who serves them.
func listenNamedPipe(name string) (net.Listener, string, error) {
var errs []error
for _, path := range daemonaddr.PipePaths(name) {
listener, err := winio.ListenPipe(path, &winio.PipeConfig{
SecurityDescriptor: ipcauth.DefaultPipeSDDL(),
})
if err != nil {
log.Debugf("not serving the daemon on %s: %v", path, err)
errs = append(errs, fmt.Errorf("%s: %w", path, err))
continue
}
return listener, path, nil
}
return nil, "", errors.Join(errs...)
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Ensure a single daemon instance: stop the service first (netbird service stop / Stop-Service netbird)
- Run the daemon elevated if the protected pipe name is required
- Choose a different --daemon-addr pipe name to avoid the collision
- Read each joined error: access denied points to privileges, pipe-busy/file-in-use points to an existing listener
Defensive patterns
Strategy: fallback
Validate before calling
for _, p := range daemonaddr.PipePaths(name) {
if c, err := winio.DialPipe(p, &winio.DialPipeTimeout{Timeout: 100 * time.Millisecond}); err == nil {
_ = c.Close()
return fmt.Errorf("pipe %s already served by another daemon", p)
}
} Try / catch
listener, path, err := listenNamedPipe(name)
if err != nil {
// both candidate names failed; the joined errors distinguish privileges from an existing listener
if isAccessDenied(err) {
return retryElevated()
}
return fallbackToTCPIfAllowed()
} Prevention
- Guarantee one daemon instance per machine before starting another
- Stop the installed service before running the daemon in the foreground
- Prefer the protected pipe name and run the service as LocalSystem
When it happens
Trigger: Another netbird daemon already listening on the pipe names (service running while `service run` or the embedded daemon starts); a security descriptor rejected for the caller's token; a malformed pipe name.
Common situations: Starting a second daemon while the installed Windows service is active; running the netstack/embedded client concurrently with the service.
Related errors
- named pipes are only supported on Windows
- management client is not initialised
- service is not up
- client not initialized
- engine not started
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/257df4c5cf8c1e0f.
Report an issue: GitHub.