XTLS/Xray-core · error

KeepAlivePeriod must be between 2 and 60

Error message

KeepAlivePeriod must be between 2 and 60

What it means

Range check on finalMask.quicParams.keepAlivePeriod: if set (non-zero) it must be between 2 and 60 inclusive (seconds). This guards against keepalive intervals so short they flood the link or so long they fail to keep NAT mappings alive.

Source

Thrown at infra/conf/transport_internet.go:276

			}

			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")
			}

			if c.FinalMask.QuicParams.Debug {
				os.Setenv("HYSTERIA_BBR_DEBUG", "true")
				os.Setenv("HYSTERIA_BRUTAL_DEBUG", "true")
			}

			config.QuicParams = &internet.QuicParams{
				Congestion: c.FinalMask.QuicParams.Congestion,
				BbrProfile: profile,
				BrutalUp:   up,
				BrutalDown: down,
				UdpHop: &internet.UdpHop{
					Ports:       c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(),
					IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From),

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Set keepAlivePeriod in [2, 60] seconds (e.g. 15 or 30).
  2. Or leave it unset for the default.
  3. Ensure keepAlivePeriod < maxIdleTimeout so pings arrive before idle disconnect.

Example fix

// before
"quicParams": { "keepAlivePeriod": 1 }
// after
"quicParams": { "keepAlivePeriod": 15 }
Defensive patterns

Strategy: validation

Validate before calling

func keepAlivePeriodOK(qp map[string]any) bool {
    v, ok := qp["keepAlivePeriod"].(float64)
    return !ok || v == 0 || (v >= 2 && v <= 60)
}

Prevention

When it happens

Trigger: "quicParams": { "keepAlivePeriod": 1 } or "keepAlivePeriod": 90 }.

Common situations: Sub-second values entered as milliseconds; syncing keepAlive with maxIdleTimeout incorrectly (keepAlive should be well below idle timeout); copying wireguard-style persistent-keepalive values.

Related errors


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