{"record":{"id":"f0e68d83ccca8d04","repo":"gastownhall/beads","slug":"accept-w","errorCode":null,"errorMessage":"accept: %w","messagePattern":"accept: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/server.go","lineNumber":416,"sourceCode":"\t}\n}\n\nfunc (p *proxyServer) acceptLoop(ctx context.Context) error {\n\tp.tracef(\"acceptLoop start (addr=%s)\", p.listener.Addr())\n\tfor {\n\t\tconn, err := p.listener.Accept()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, net.ErrClosed) || ctx.Err() != nil {\n\t\t\t\tp.tracef(\"acceptLoop exit (ctx=%v)\", ctx.Err())\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t// Surface non-shutdown accept errors to the errgroup so the\n\t\t\t// proxy fails fast instead of busy-looping. Specific errors that\n\t\t\t// warrant retry (e.g. transient EMFILE under load) can be added\n\t\t\t// here as the need arises.\n\t\t\tp.tracef(\"acceptLoop error: %v\", err)\n\t\t\tp.stats.IncAcceptError()\n\t\t\treturn fmt.Errorf(\"accept: %w\", err)\n\t\t}\n\t\tif tc, ok := conn.(*net.TCPConn); ok {\n\t\t\t_ = tc.SetKeepAlive(true)\n\t\t\t_ = tc.SetKeepAlivePeriod(tcpKeepAlivePeriod)\n\t\t}\n\t\tp.tracef(\"acceptLoop accepted (remote=%s)\", conn.RemoteAddr())\n\t\tp.stats.IncAccept()\n\t\tp.conns.Go(func() error {\n\t\t\treturn p.handleConn(ctx, conn)\n\t\t})\n\t}\n}\n\nfunc (p *proxyServer) handleConn(ctx context.Context, client net.Conn) error {\n\taddr := client.RemoteAddr()\n\tp.tracef(\"handleConn(%s) start\", addr)\n\tp.activeConns.Add(1)\n\tdefer func() {","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/server.go#L398-L434","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: proxy dies on transient EMFILE\nreturn fmt.Errorf(\"accept: %w\", err)\n// after (suggested by the code comment): retry transient errors\nif errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE) {\n    time.Sleep(50 * time.Millisecond)\n    continue\n}\nreturn fmt.Errorf(\"accept: %w\", err)","handlingStrategy":"fallback","validationCode":"var l sysctlFDLimit\nif err := unix.Getrlimit(unix.RLIMIT_NOFILE, &l); err == nil && l.Cur < 4096 {\n    return fmt.Errorf(\"raise nofile limit before starting proxy (current %d)\", l.Cur)\n}","typeGuard":null,"tryCatchPattern":"if err := proxy.ListenAndServe(ctx, ...); err != nil {\n    if strings.Contains(err.Error(), \"accept:\") {\n        // check ulimit -n / fd leaks, fix, and restart the proxy\n        return fmt.Errorf(\"proxy died on accept: %w\", err)\n    }\n    return err\n}","preventionTips":["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=...)\nSupervise the proxy (systemd/restart policy) since it fails fast on accept errors"],"tags":["go","network","tcp","accept","file-descriptors"],"backgroundTag":"accept-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}