XTLS/Xray-core · critical
hopIntervalMax < hopIntervalMin
Error message
hopIntervalMax < hopIntervalMin
What it means
NewPacketConn for hysteria UDP port-hopping panics because hopIntervalMax < hopIntervalMin after defaults are applied. Both intervals default when zero and must each be >= 5s; if a caller passes e.g. min=30s max=10s, the max<min invariant trips and the constructor panics with this literal message.
Source
Thrown at transport/internet/hysteria/udphop/conn.go:66
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error), currentConn net.PacketConn, addrIndex int) net.PacketConn {
if len(addrs) == 0 {
panic("len(addrs) == 0")
}
if hopIntervalMin == 0 {
hopIntervalMin = defaultHopInterval
}
if hopIntervalMax == 0 {
hopIntervalMax = defaultHopInterval
}
if hopIntervalMin < 5*time.Second {
panic("hopIntervalMin < 5*time.Second")
}
if hopIntervalMax < 5*time.Second {
panic("hopIntervalMax < 5*time.Second")
}
if hopIntervalMax < hopIntervalMin {
panic("hopIntervalMax < hopIntervalMin")
}
if listenUDPFunc == nil {
panic("listenUDPFunc is nil")
}
hConn := &UdpHopPacketConn{
Addrs: addrs,
HopIntervalMin: hopIntervalMin,
HopIntervalMax: hopIntervalMax,
ListenUDPFunc: listenUDPFunc,
prevConn: nil,
currentConn: currentConn,
addrIndex: addrIndex,
recvQueue: make(chan *udpPacket, packetQueueSize),
closeChan: make(chan struct{}),
bufPool: sync.Pool{
New: func() interface{} {
return make([]byte, udpBufferSize)
},View on GitHub (pinned to 7d214f8b09)
Solutions
- Set hopIntervalMax >= hopIntervalMin (both >= 5s), e.g. min 30s / max 60s.
- If you want a single fixed interval, pass the same value for both or leave both zero for defaults.
- Swap-check any config template: min comes first in the parameter list and in the config schema.
Example fix
// before conn, err := udphop.NewPacketConn(addrs, 60*time.Second /*min*/, 30*time.Second /*max*/, ...) // after conn, err := udphop.NewPacketConn(addrs, 30*time.Second /*min*/, 60*time.Second /*max*/, ...)
Defensive patterns
Strategy: validation
Validate before calling
if hopIntervalMax < hopIntervalMin {
return nil, fmt.Errorf("hop intervals invalid: max %v < min %v (both must be >= 5s)", hopIntervalMax, hopIntervalMin)
}
if hopIntervalMin < 5*time.Second || hopIntervalMax < 5*time.Second {
return nil, errors.New("hop intervals must be >= 5s")
} Try / catch
defer func() {
if r := recover(); r != nil {
return nil, fmt.Errorf("udphop conn rejected (min=%v max=%v): %v", hopIntervalMin, hopIntervalMax, r)
}
}() Prevention
- Order config fields min-then-max and double-check after editing hop intervals.
- Keep both values >= 5s; leave both unset/zero to take defaults.
- Validate interval pairs at config load instead of relying on the constructor panic.
When it happens
Trigger: Constructing udphop.NewPacketConn with hopIntervalMin > hopIntervalMax (directly, or min set high with max left at a value below it); config parsed as {"hopInterval": ...} where min/max got swapped or one defaulted while the other was raised above 5–30s defaults.
Common situations: YAML/JSON fields hop_interval_min/max transcribed in the wrong order; raising min for stability while forgetting max defaults; unit tests constructing the conn directly with arbitrary intervals.
Related errors
- version != 2
- Failed to build Hysteria config.
- unsupported unit:
- version != 2
- UdpIdleTimeout must be between 2 and 600
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/496f64473a392729.
Report an issue: GitHub.