XTLS/Xray-core · critical
brutal
Error message
brutal
What it means
Same unrecognized-congestion panic as the dialer, but on the inbound side: QListener.Accept panics with l.quicParams.Congestion the first time a QUIC client connects, because the per-conn congestion setup switch has the same default: panic branch. The listener itself starts fine — the crash is deferred until the first Accept, which makes it especially surprising.
Source
Thrown at transport/internet/splithttp/hub.go:627
type QListener struct {
http3.QUICListener
quicParams *internet.QuicParams
}
func (l *QListener) Accept(ctx context.Context) (*quic.Conn, error) {
conn, err := l.QUICListener.Accept(ctx)
if err != nil {
return nil, err
}
switch l.quicParams.Congestion {
case "reno":
case "", "bbr":
congestion.UseBBR(conn, bbr.Profile(l.quicParams.BbrProfile))
case "force-brutal":
congestion.UseBrutal(conn, l.quicParams.BrutalUp)
default:
panic(l.quicParams.Congestion)
}
return conn, nil
}
View on GitHub (pinned to 7d214f8b09)
Solutions
- Set congestion to "reno", "bbr"/"", or "force-brutal" (with brutalUp) in the inbound splithttp settings.
- Check both sides: the dialer (outbound) and hub (inbound) each validate independently; fix both if the config is shared.
- Add startup validation of the congestion field so misconfiguration fails before any client connects.
Example fix
// before (inbound config) "congestion": "brutal" // after "congestion": "bbr"
Defensive patterns
Strategy: validation
Validate before calling
validCongestion := map[string]bool{"": true, "reno": true, "bbr": true, "force-brutal": true}
if !validCongestion[l.quicParams.Congestion] {
return nil, fmt.Errorf("hub: invalid congestion %q on inbound splithttp", l.quicParams.Congestion)
} Prevention
- Validate the inbound hub's congestion field at listener construction, since the panic hides until first Accept.
- Fix both dialer and hub when correcting the config; they validate independently.
- Smoke-test a real connection after every transport config change — startup success proves nothing here.
When it happens
Trigger: Starting a splithttp (HTTP/3 mode) hub with congestion set to anything other than "reno", ""/"bbr", "force-brutal"; the process panics inside Accept when the first inbound QUIC connection arrives.
Common situations: Server config edited to "brutal"/"cubic"/misspelled value; config validated at startup passes because the string is only interpreted lazily per accepted connection.
Related errors
- brutal
- force-brutal requires up
- unknown congestion control: + c.FinalMask.QuicParams.Conges
- `scMaxEachPostBytes` should be bigger than 0
- unknown bbr profile
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/184f1dcdfa47ebf2.
Report an issue: GitHub.