{"record":{"id":"009adc9ef9b1e3b1","repo":"XTLS/Xray-core","slug":"packetsfrom-can-t-be-0-009adc","errorCode":null,"errorMessage":"PacketsFrom can't be 0","messagePattern":"PacketsFrom can't be 0","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_finalmask.go","lineNumber":261,"sourceCode":"func (c *FragmentMask) Build() (proto.Message, error) {\n\tconfig := &fragment.Config{}\n\n\tswitch strings.ToLower(c.Packets) {\n\tcase \"tlshello\":\n\t\tconfig.PacketsFrom = 0\n\t\tconfig.PacketsTo = 1\n\tcase \"\":\n\t\tconfig.PacketsFrom = 0\n\t\tconfig.PacketsTo = 0\n\tdefault:\n\t\tfrom, to, err := ParseRangeString(c.Packets)\n\t\tif err != nil {\n\t\t\treturn nil, errors.New(\"Invalid PacketsFrom\").Base(err)\n\t\t}\n\t\tconfig.PacketsFrom = int64(from)\n\t\tconfig.PacketsTo = int64(to)\n\t\tif config.PacketsFrom == 0 {\n\t\t\treturn nil, errors.New(\"PacketsFrom can't be 0\")\n\t\t}\n\t}\n\n\tif len(c.Lengths) > 0 {\n\t\tfor _, r := range c.Lengths {\n\t\t\tconfig.LengthsMin = append(config.LengthsMin, int64(r.From))\n\t\t\tconfig.LengthsMax = append(config.LengthsMax, int64(r.To))\n\t\t}\n\t} else {\n\t\tconfig.LengthsMin = append(config.LengthsMin, int64(c.Length.From))\n\t\tconfig.LengthsMax = append(config.LengthsMax, int64(c.Length.To))\n\t}\n\n\tif config.LengthsMin[len(config.LengthsMin)-1] == 0 {\n\t\treturn nil, errors.New(\"last lengths entry min can't be 0\")\n\t}\n\n\tif len(c.Delays) > 0 {","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_finalmask.go#L243-L279","documentation":"After successfully parsing \"packets\" as a numeric range, FragmentMask.Build (infra/conf/transport_finalmask.go:261) rejects a range whose lower bound is 0: packet indices are 1-based, so a fragment starting at packet 0 is meaningless and \"PacketsFrom can't be 0\" aborts the build.","triggerScenarios":"\"packets\":\"0-2\" or \"packets\":\"0\". Note \"tlshello\" and \"\" set from=0 internally but bypass this check; only explicit numeric ranges starting at 0 are rejected.","commonSituations":"Zero-indexed thinking (first packet = 0); config generators emitting 0-based inclusive ranges; copying \"0-1\" from snippets that predate the check.","solutions":["Start the range at 1: \"packets\":\"1-2\"","Use \"packets\":\"tlshello\" if the goal is just ClientHello fragmentation"],"exampleFix":"// before\n\"packets\": \"0-1\"\n// after\n\"packets\": \"1-1\"","handlingStrategy":"validation","validationCode":"const m = /^(\\d+)(?:-(\\d+))?$/.exec(cfg.packets ?? '');\nif (m && parseInt(m[1], 10) === 0) throw new Error('packet indices are 1-based; got 0');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat packet indices as 1-based","Prefer tlshello unless specific packet indices are required"],"tags":["xray","go","transport","fragment","validation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}