{"record":{"id":"7587e6cef25f03ce","repo":"XTLS/Xray-core","slug":"variant-d-has-no-chunks","errorCode":null,"errorMessage":"variant %d has no chunks","messagePattern":"variant (.+?) has no chunks","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/padding.go","lineNumber":336,"sourceCode":"\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)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlength := paddingVariantLength(variant)\n\t\tif length > maxPaddingTurnLength {\n\t\t\treturn 0, 0, fmt.Errorf(\"variant %d is too long: %d\", i, length)\n\t\t}","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/padding.go#L318-L354","documentation":"When a paddingTurn uses variants, each variant must contain at least one chunk defining its record layout; this error names the variant index whose chunks slice is empty. An empty variant has no length and no delays, so bounds computation and framing would be undefined.","triggerScenarios":"Appending paddingVariant{} or a variant built from an empty []int to turn.variants; programmatic variant construction where a loop accidentally appends the zero value.","commonSituations":"Generating variants from user config where an empty chunk list passes through unvalidated; refactoring presets and leaving a placeholder empty variant behind.","solutions":["Give every variant at least one chunk of length 1..49152 (maxPaddingChunkLength).","Filter out empty variants before building the schedule.","Add a config-side check: reject padding entries with an empty chunks array at load time."],"exampleFix":"// before\nvariants = append(variants, paddingVariant{})\n// after\nvariants = append(variants, paddingVariant{chunks: []int{256}})","handlingStrategy":"validation","validationCode":"for i, v := range turn.variants {\n    if len(v.chunks) == 0 {\n        return fmt.Errorf(\"variant %d empty\", i)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter empty variant entries before schedule construction.","Validate chunk lengths (1..49152) in the same pass.","Reject empty chunks arrays in user-facing config parsing."],"tags":["go","configuration","validation","padding"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}