{"record":{"id":"8bf97f5d401450e6","repo":"XTLS/Xray-core","slug":"variants-cannot-be-combined-with-a-length-range","errorCode":null,"errorMessage":"variants cannot be combined with a length range","messagePattern":"variants cannot be combined with a length range","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/padding.go","lineNumber":329,"sourceCode":"func defaultPaddingChunks(recordLength, writeChunkLength int) []int {\n\tchunks := make([]int, 0, (recordLength+writeChunkLength-1)/writeChunkLength)\n\tfor remaining := recordLength; remaining > 0; {\n\t\tchunkLength := min(remaining, writeChunkLength)\n\t\tchunks = append(chunks, chunkLength)\n\t\tremaining -= chunkLength\n\t}\n\treturn chunks\n}\n\nfunc paddingTurnBounds(turn paddingTurn) (int, int, error) {\n\tif len(turn.variants) == 0 {\n\t\tif turn.minLength < 1 || turn.maxLength < turn.minLength || turn.maxLength > maxPaddingTurnLength {\n\t\t\treturn 0, 0, fmt.Errorf(\"invalid range: %d-%d\", turn.minLength, turn.maxLength)\n\t\t}\n\t\treturn turn.minLength, turn.maxLength, nil\n\t}\n\tif turn.minLength != 0 || turn.maxLength != 0 {\n\t\treturn 0, 0, fmt.Errorf(\"variants cannot be combined with a length range\")\n\t}\n\n\tminLength := maxPaddingTurnLength + 1\n\tmaxLength := 0\n\tfor i, variant := range turn.variants {\n\t\tif len(variant.chunks) == 0 {\n\t\t\treturn 0, 0, fmt.Errorf(\"variant %d has no chunks\", i)\n\t\t}\n\t\tif len(variant.delays) != 0 && len(variant.delays) != len(variant.chunks) {\n\t\t\treturn 0, 0, fmt.Errorf(\"variant %d has %d chunks and %d delays\", i, len(variant.chunks), len(variant.delays))\n\t\t}\n\t\tfor j, chunkLength := range variant.chunks {\n\t\t\tif chunkLength < 1 || chunkLength > maxPaddingChunkLength {\n\t\t\t\treturn 0, 0, fmt.Errorf(\"variant %d chunk %d has invalid length: %d\", i, j, chunkLength)\n\t\t\t}\n\t\t\tif len(variant.delays) > 0 {\n\t\t\t\tif err := validatePaddingDelayRange(variant.delays[j]); err != nil {\n\t\t\t\t\treturn 0, 0, fmt.Errorf(\"variant %d chunk %d has an invalid delay: %w\", i, j, err)","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/padding.go#L311-L347","documentation":"A paddingTurn can describe its lengths either as an explicit minLength/maxLength range or as a list of concrete variants, but not both. This error fires in paddingTurnBounds when variants are present and either bound field is non-zero, because the two sources of length bounds would conflict.","triggerScenarios":"Constructing a paddingTurn with a non-empty variants slice while minLength or maxLength is also set (non-zero); e.g. appending a range to a variant-based preset turn, or leaving a stale MaxLength in shared config JSON.","commonSituations":"Merging a variants-based preset with a config template that still carries min/max padding fields; YAML/JSON config where empty range defaults serialize as 0 but an explicit value survives an edit.","solutions":["Pick one representation: remove minLength/maxLength (leave both 0) when using variants.","Or drop the variants slice and express the turn as a plain length range.","Sanitize config loading to zero out bounds when variants are detected, if configs come from users."],"exampleFix":"// before\nturn := paddingTurn{minLength: 64, maxLength: 64, variants: vs}\n// after\nturn := paddingTurn{variants: vs}","handlingStrategy":"validation","validationCode":"if len(turn.variants) > 0 && (turn.minLength != 0 || turn.maxLength != 0) {\n    return errors.New(\"turn declares both variants and a length range\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Zero out min/max fields whenever a variants list is set.","In config loaders, reject JSON objects containing both keys.","Add a linter/test over generated schedules asserting mutual exclusivity."],"tags":["go","configuration","validation","padding"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}