XTLS/Xray-core · error
force-brutal requires up
Error message
force-brutal requires up
What it means
Thrown when congestion is set to "force-brutal" but brutalUp is 0/unset. force-brutal means the connection must use Brutal CC with a fixed send rate, so an upstream bandwidth is mandatory. The check runs after the Brutal floor checks and before the QUIC numeric range checks.
Source
Thrown at infra/conf/transport_internet.go:250
}
down, err := c.FinalMask.QuicParams.BrutalDown.Bps()
if err != nil {
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")
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Add a brutalUp value of at least 65536 B/s alongside congestion: "force-brutal".
- Or use plain "brutal" if you do not want to force a fixed upstream rate.
- Verify brutalUp parses (e.g. "10 MBps"); an unparsable string errors earlier in Bps().
Example fix
// before
"quicParams": { "congestion": "force-brutal", "brutalDown": "1 MBps" }
// after
"quicParams": { "congestion": "force-brutal", "brutalUp": "5 MBps", "brutalDown": "1 MBps" } Defensive patterns
Strategy: validation
Validate before calling
func forceBrutalSatisfied(qp map[string]any) bool {
c, _ := qp["congestion"].(string)
if strings.ToLower(c) != "force-brutal" { return true }
up, _ := qp["brutalUp"].(string)
bps, err := parseBandwidthToBytesPerSec(up)
return err == nil && bps > 0
} Prevention
- Treat 'force-brutal implies brutalUp' as a pair in config templates.
- Prefer 'brutal' unless a fixed upstream rate is explicitly required.
- Test-render configs with a validator that knows the congestion rules.
When it happens
Trigger: "quicParams": { "congestion": "force-brutal" } with no brutalUp field (or brutalUp explicitly 0).
Common situations: Setting only brutalDown for a download-heavy server profile; assuming the server infers the up rate; renaming from "brutal" to "force-brutal" without adding bandwidth.
Related errors
- BrutalUp must be at least 65536 bytes per second
- BrutalDown must be at least 65536 bytes per second
- unknown congestion control: + c.FinalMask.QuicParams.Conges
- unknown bbr profile
- Interval must be at least 5
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/cc0a3f958d2c4a41.
Report an issue: GitHub.