XTLS/Xray-core · error
unknown congestion control: + c.FinalMask.QuicParams.Conges
Error message
unknown congestion control: + c.FinalMask.QuicParams.Congestion + , valid values: reno, bbr, brutal, force-brutal
What it means
Enumerates the allowed congestion control algorithms for finalMask.quicParams: '', 'brutal', 'reno', 'bbr', and 'force-brutal' (the latter additionally requires brutalUp). The value is lowercased first, so case does not matter, but any other string is rejected with the valid values listed in the message.
Source
Thrown at infra/conf/transport_internet.go:253
return nil, err
}
if up > 0 && up < 65536 {
return nil, errors.New("BrutalUp must be at least 65536 bytes per second")
}
if down > 0 && down < 65536 {
return nil, errors.New("BrutalDown must be at least 65536 bytes per second")
}
c.FinalMask.QuicParams.Congestion = strings.ToLower(c.FinalMask.QuicParams.Congestion)
switch c.FinalMask.QuicParams.Congestion {
case "", "brutal", "reno", "bbr":
case "force-brutal":
if up == 0 {
return nil, errors.New("force-brutal requires up")
}
default:
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
}
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
return nil, errors.New("Interval must be at least 5")
}
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.MaxStreamReceiveWindow > 0 && c.FinalMask.QuicParams.MaxStreamReceiveWindow < 16384 {
return nil, errors.New("MaxStreamReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.InitConnectionReceiveWindow > 0 && c.FinalMask.QuicParams.InitConnectionReceiveWindow < 16384 {
return nil, errors.New("InitConnectionReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.MaxConnectionReceiveWindow > 0 && c.FinalMask.QuicParams.MaxConnectionReceiveWindow < 16384 {
return nil, errors.New("MaxConnectionReceiveWindow must be at least 16384")
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Set congestion to one of: "reno", "bbr", "brutal", "force-brutal" (case-insensitive).
- Remove the field to use the default (empty string is accepted).
- If you intended fixed-rate, use "force-brutal" and also set brutalUp >= 65536 B/s.
Example fix
// before
"quicParams": { "congestion": "cubic" }
// after
"quicParams": { "congestion": "bbr" } Defensive patterns
Strategy: validation
Validate before calling
var validCongestion = map[string]bool{"": true, "brutal": true, "reno": true, "bbr": true, "force-brutal": true}
func congestionOK(qp map[string]any) bool {
c, _ := qp["congestion"].(string)
return validCongestion[strings.ToLower(c)]
} Type guard
type Congestion string
func (c Congestion) Valid() bool {
switch strings.ToLower(string(c)) {
case "", "brutal", "reno", "bbr", "force-brutal":
return true
}
return false
} Prevention
- Offer congestion control as a dropdown/enum in tooling, never free text.
- Remember only four values exist; standard QUIC names like cubic are not supported.
- Lowercase user input before validating (the builder is case-insensitive).
When it happens
Trigger: "quicParams": { "congestion": "cubic" } or any string other than reno/bbr/brutal/force-brutal.
Common situations: Assuming standard QUIC names like 'cubic' or 'newreno' are supported; typos ('bbrr', 'Bruno'); leftover experimental names from older forks.
Related errors
- force-brutal requires up
- unknown bbr profile
- BrutalUp must be at least 65536 bytes per second
- BrutalDown must be at least 65536 bytes per second
- Interval must be at least 5
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/c99ccf7e5905cfba.
Report an issue: GitHub.