XTLS/Xray-core · error
MaxIdleTimeout must be between 4 and 120
Error message
MaxIdleTimeout must be between 4 and 120
What it means
Range check on finalMask.quicParams.maxIdleTimeout: if set (non-zero) it must be between 4 and 120 inclusive; anything outside is rejected. The unit is seconds per the schema. Values below 4s would drop connections on transient stalls; above 120s keep dead connections too long.
Source
Thrown at infra/conf/transport_internet.go:273
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")
}
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,View on GitHub (pinned to 7d214f8b09)
Solutions
- Set maxIdleTimeout to a value in [4, 120] seconds (30 is a common choice).
- Or remove the field (0) to use the default.
- Confirm the unit is seconds, not milliseconds.
Example fix
// before
"quicParams": { "maxIdleTimeout": 300000 }
// after
"quicParams": { "maxIdleTimeout": 30 } Defensive patterns
Strategy: validation
Validate before calling
func maxIdleTimeoutOK(qp map[string]any) bool {
v, ok := qp["maxIdleTimeout"].(float64)
return !ok || v == 0 || (v >= 4 && v <= 120)
} Prevention
- Remember the unit is seconds and the window is [4, 120].
- Keep keepAlivePeriod < maxIdleTimeout.
- Omit the field when the default is acceptable.
When it happens
Trigger: "quicParams": { "maxIdleTimeout": 2 } or "maxIdleTimeout": 300 }.
Common situations: Passing milliseconds (e.g. 300000) where seconds are expected; aggressive NAT-friendly tuning below the floor; mirroring TCP keepalive values.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- unknown bbr profile
- BrutalUp must be at least 65536 bytes per second
- BrutalDown must be at least 65536 bytes per second
- force-brutal requires up
- unknown congestion control: + c.FinalMask.QuicParams.Conges
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/c90d2203338627e9.
Report an issue: GitHub.