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

  1. Add a brutalUp value of at least 65536 B/s alongside congestion: "force-brutal".
  2. Or use plain "brutal" if you do not want to force a fixed upstream rate.
  3. 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

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


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/cc0a3f958d2c4a41. Report an issue: GitHub.