gastownhall/beads · error
accept: %w
Error message
accept: %w
What it means
acceptLoop exits the whole proxy when listener.Accept() returns a non-shutdown error (anything other than net.ErrClosed or a cancelled context). The error is wrapped as 'accept: %w' so the errgroup fails fast instead of busy-looping on a broken listener. Transient retriable conditions (e.g. EMFILE under load) are deliberately not yet retried.
Source
Thrown at internal/storage/dbproxy/proxy/server.go:416
}
}
func (p *proxyServer) acceptLoop(ctx context.Context) error {
p.tracef("acceptLoop start (addr=%s)", p.listener.Addr())
for {
conn, err := p.listener.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) || ctx.Err() != nil {
p.tracef("acceptLoop exit (ctx=%v)", ctx.Err())
return nil
}
// Surface non-shutdown accept errors to the errgroup so the
// proxy fails fast instead of busy-looping. Specific errors that
// warrant retry (e.g. transient EMFILE under load) can be added
// here as the need arises.
p.tracef("acceptLoop error: %v", err)
p.stats.IncAcceptError()
return fmt.Errorf("accept: %w", err)
}
if tc, ok := conn.(*net.TCPConn); ok {
_ = tc.SetKeepAlive(true)
_ = tc.SetKeepAlivePeriod(tcpKeepAlivePeriod)
}
p.tracef("acceptLoop accepted (remote=%s)", conn.RemoteAddr())
p.stats.IncAccept()
p.conns.Go(func() error {
return p.handleConn(ctx, conn)
})
}
}
func (p *proxyServer) handleConn(ctx context.Context, client net.Conn) error {
addr := client.RemoteAddr()
p.tracef("handleConn(%s) start", addr)
p.activeConns.Add(1)
defer func() {View on GitHub (pinned to 71377f2769)
Solutions
- Raise the process/file-descriptor limit (ulimit -n 65536 or the container's nofile limit) and restart the proxy.
- Check for fd leaks (lsof -p <pid> | wc -l) in the process running the proxy.
- Restart the proxy after fixing the condition; it exits by design on this error.
- If EMFILE is recurring under load, add a retriable-error branch in acceptLoop (the code comments suggest extending this) instead of failing fast.
- Verify the listen address/interface still exists if errors reference address problems.
Example fix
// before: proxy dies on transient EMFILE
return fmt.Errorf("accept: %w", err)
// after (suggested by the code comment): retry transient errors
if errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE) {
time.Sleep(50 * time.Millisecond)
continue
}
return fmt.Errorf("accept: %w", err) Defensive patterns
Strategy: fallback
Validate before calling
var l sysctlFDLimit
if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &l); err == nil && l.Cur < 4096 {
return fmt.Errorf("raise nofile limit before starting proxy (current %d)", l.Cur)
} Try / catch
if err := proxy.ListenAndServe(ctx, ...); err != nil {
if strings.Contains(err.Error(), "accept:") {
// check ulimit -n / fd leaks, fix, and restart the proxy
return fmt.Errorf("proxy died on accept: %w", err)
}
return err
} Prevention
- Raise RLIMIT_NOFILE (ulimit -n) for the process running the proxy
- Audit for file-descriptor leaks with lsof
- Set adequate container fd limits (docker --ulimit nofile=...) Supervise the proxy (systemd/restart policy) since it fails fast on accept errors
When it happens
Trigger: The TCP listener hits a fatal accept error: file-descriptor exhaustion (EMFILE/ENFILE), the listen socket becoming invalid, or an OS-level network error on Accept while the proxy is not shutting down.
Common situations: ulimit -n too low while many clients connect; a leak of file descriptors in the same process; container fd limits; sudden interface/address removal causing accept failures.
Related errors
- ensureProxiedServerConfig: pick free port: %w
- server: DoltServer.Dial: %w
- server: ExternalDoltServer.Dial: %w
- failed to remove backup: %w
- pull: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f0e68d83ccca8d04.
Report an issue: GitHub.