XTLS/Xray-core · error

InitStreamReceiveWindow must be at least 16384

Error message

InitStreamReceiveWindow must be at least 16384

What it means

QUIC flow-control floor for finalMask.quicParams.initStreamReceiveWindow: any positive value below 16384 bytes is rejected (0 = use default). quic-go requires stream receive windows of at least 16 KiB; smaller windows would break the QUIC transport.

Source

Thrown at infra/conf/transport_internet.go:261

			}

			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")
			}
			if c.FinalMask.QuicParams.MaxIdleTimeout != 0 && (c.FinalMask.QuicParams.MaxIdleTimeout < 4 || c.FinalMask.QuicParams.MaxIdleTimeout > 120) {
				return nil, errors.New("MaxIdleTimeout must be between 4 and 120")
			}
			if c.FinalMask.QuicParams.KeepAlivePeriod != 0 && (c.FinalMask.QuicParams.KeepAlivePeriod < 2 || c.FinalMask.QuicParams.KeepAlivePeriod > 60) {
				return nil, errors.New("KeepAlivePeriod must be between 2 and 60")
			}
			if c.FinalMask.QuicParams.MaxIncomingStreams != 0 && c.FinalMask.QuicParams.MaxIncomingStreams < 8 {
				return nil, errors.New("MaxIncomingStreams must be at least 8")

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Set initStreamReceiveWindow to >= 16384 (bytes), e.g. 8192 KiB style values used in examples (e.g. 8388608).
  2. Or omit the field to use the library default.
  3. Prefer tuning maxStreamReceiveWindow rather than shrinking the initial window below the floor.

Example fix

// before
"quicParams": { "initStreamReceiveWindow": 8192 }
// after
"quicParams": { "initStreamReceiveWindow": 8388608 }
Defensive patterns

Strategy: validation

Validate before calling

func windowFloorOK(v any, floor int64) bool {
    n, ok := v.(float64)
    return !ok || n == 0 || int64(n) >= floor
}
// usage: windowFloorOK(qp["initStreamReceiveWindow"], 16384)

Prevention

When it happens

Trigger: "quicParams": { "initStreamReceiveWindow": 8192 }.

Common situations: Trying to reduce memory by shrinking windows below the protocol minimum; unit confusion (bits vs bytes); carry-over values tuned for TCP buffers.

Related errors


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