{"record":{"id":"583b04e3123354c5","repo":"XTLS/Xray-core","slug":"invalid-randrange","errorCode":null,"errorMessage":"invalid randRange","messagePattern":"invalid randRange","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_finalmask.go","lineNumber":129,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\tfor _, value := range c.Servers {\n\t\tfor _, item := range value {\n\t\t\tif err := validateCustomItemSpec(item.Capture, item.Packet, item.Rand, item.Reuse, item.Transform); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\tfor _, value := range c.Errors {\n\t\tfor _, item := range value {\n\t\t\tif err := validateCustomItemSpec(item.Capture, item.Packet, item.Rand, item.Reuse, item.Transform); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\terrInvalidRange := errors.New(\"invalid randRange\")\n\n\tclients := make([]*custom.TCPSequence, len(c.Clients))\n\tfor i, value := range c.Clients {\n\t\tclients[i] = &custom.TCPSequence{}\n\t\tfor _, item := range value {\n\t\t\tif item.RandRange == nil {\n\t\t\t\titem.RandRange = &Int32Range{From: 0, To: 255}\n\t\t\t}\n\t\t\tif item.RandRange.From < 0 || item.RandRange.To > 255 {\n\t\t\t\treturn nil, errInvalidRange\n\t\t\t}\n\t\t\tvar err error\n\t\t\tif item.Packet, err = PraseByteSlice(item.Packet, item.Type); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ttransform, err := buildCustomTransform(item.Transform)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_finalmask.go#L111-L147","documentation":"HeaderCustomTCP.Build (infra/conf/transport_finalmask.go:129-145) validates each clients[i][j].randRange before converting it into custom.TCPSequence bytes. randRange defaults to {from:0,to:255} when omitted, and any explicit range with from<0 or to>255 is rejected with \"invalid randRange\" because it indexes individual bytes of a TCP payload.","triggerScenarios":"A tcpmask \"header-custom\" clients entry with \"randRange\":{\"from\":-1,...} or {\"to\":256}; also any typo making To parse large. Only the clients loop shown validates (servers/errors items go through the same builder path with their own defaults).","commonSituations":"Users assuming randRange is a packet-length range in bytes (thousands) rather than a per-byte value range 0-255; copying rand semantics from the \"rand\" count field; negative \"from\" copied from delay ranges where negatives are tolerated.","solutions":["Keep randRange within 0..255 inclusive, e.g. {\"from\":32,\"to\":126}","Omit randRange entirely to accept the 0-255 default","Use \"rand\" (count of random bytes) for length control, not randRange"],"exampleFix":"// before\n\"randRange\": { \"from\": 0, \"to\": 65535 }\n// after\n\"randRange\": { \"from\": 0, \"to\": 255 }","handlingStrategy":"validation","validationCode":"for (const seq of cfg.clients ?? []) for (const it of seq) {\n  const rr = it.randRange ?? {from:0, to:255};\n  if (rr.from < 0 || rr.to > 255) throw new Error(`randRange must be within 0-255, got ${rr.from}-${rr.to}`);\n}","typeGuard":"const inByteRange = (r:{from:number;to:number}) => r.from >= 0 && r.to <= 255;","tryCatchPattern":null,"preventionTips":["Remember randRange = byte VALUES, not counts","Share one validator for clients/servers/errors arrays"],"tags":["xray","go","transport","header-custom","validation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}