{"record":{"id":"496f64473a392729","repo":"XTLS/Xray-core","slug":"hopintervalmax-hopintervalmin","errorCode":null,"errorMessage":"hopIntervalMax < hopIntervalMin","messagePattern":"hopIntervalMax < hopIntervalMin","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"transport/internet/hysteria/udphop/conn.go","lineNumber":66,"sourceCode":"\nfunc 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 {\n\tif len(addrs) == 0 {\n\t\tpanic(\"len(addrs) == 0\")\n\t}\n\tif hopIntervalMin == 0 {\n\t\thopIntervalMin = defaultHopInterval\n\t}\n\tif hopIntervalMax == 0 {\n\t\thopIntervalMax = defaultHopInterval\n\t}\n\tif hopIntervalMin < 5*time.Second {\n\t\tpanic(\"hopIntervalMin < 5*time.Second\")\n\t}\n\tif hopIntervalMax < 5*time.Second {\n\t\tpanic(\"hopIntervalMax < 5*time.Second\")\n\t}\n\tif hopIntervalMax < hopIntervalMin {\n\t\tpanic(\"hopIntervalMax < hopIntervalMin\")\n\t}\n\tif listenUDPFunc == nil {\n\t\tpanic(\"listenUDPFunc is nil\")\n\t}\n\thConn := &UdpHopPacketConn{\n\t\tAddrs:          addrs,\n\t\tHopIntervalMin: hopIntervalMin,\n\t\tHopIntervalMax: hopIntervalMax,\n\t\tListenUDPFunc:  listenUDPFunc,\n\t\tprevConn:       nil,\n\t\tcurrentConn:    currentConn,\n\t\taddrIndex:      addrIndex,\n\t\trecvQueue:      make(chan *udpPacket, packetQueueSize),\n\t\tcloseChan:      make(chan struct{}),\n\t\tbufPool: sync.Pool{\n\t\t\tNew: func() interface{} {\n\t\t\t\treturn make([]byte, udpBufferSize)\n\t\t\t},","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/hysteria/udphop/conn.go#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconn, err := udphop.NewPacketConn(addrs, 60*time.Second /*min*/, 30*time.Second /*max*/, ...)\n// after\nconn, err := udphop.NewPacketConn(addrs, 30*time.Second /*min*/, 60*time.Second /*max*/, ...)","handlingStrategy":"validation","validationCode":"if hopIntervalMax < hopIntervalMin {\n    return nil, fmt.Errorf(\"hop intervals invalid: max %v < min %v (both must be >= 5s)\", hopIntervalMax, hopIntervalMin)\n}\nif hopIntervalMin < 5*time.Second || hopIntervalMax < 5*time.Second {\n    return nil, errors.New(\"hop intervals must be >= 5s\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        return nil, fmt.Errorf(\"udphop conn rejected (min=%v max=%v): %v\", hopIntervalMin, hopIntervalMax, r)\n    }\n}()","preventionTips":["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."],"tags":["hysteria","port-hopping","panic","config","validation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}