XTLS/Xray-core · error

variant %d has no chunks

Error message

variant %d has no chunks

What it means

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.

Source

Thrown at transport/internet/finalmask/xmc/padding.go:336

	return chunks
}

func paddingTurnBounds(turn paddingTurn) (int, int, error) {
	if len(turn.variants) == 0 {
		if turn.minLength < 1 || turn.maxLength < turn.minLength || turn.maxLength > maxPaddingTurnLength {
			return 0, 0, fmt.Errorf("invalid range: %d-%d", turn.minLength, turn.maxLength)
		}
		return turn.minLength, turn.maxLength, nil
	}
	if turn.minLength != 0 || turn.maxLength != 0 {
		return 0, 0, fmt.Errorf("variants cannot be combined with a length range")
	}

	minLength := maxPaddingTurnLength + 1
	maxLength := 0
	for i, variant := range turn.variants {
		if len(variant.chunks) == 0 {
			return 0, 0, fmt.Errorf("variant %d has no chunks", i)
		}
		if len(variant.delays) != 0 && len(variant.delays) != len(variant.chunks) {
			return 0, 0, fmt.Errorf("variant %d has %d chunks and %d delays", i, len(variant.chunks), len(variant.delays))
		}
		for j, chunkLength := range variant.chunks {
			if chunkLength < 1 || chunkLength > maxPaddingChunkLength {
				return 0, 0, fmt.Errorf("variant %d chunk %d has invalid length: %d", i, j, chunkLength)
			}
			if len(variant.delays) > 0 {
				if err := validatePaddingDelayRange(variant.delays[j]); err != nil {
					return 0, 0, fmt.Errorf("variant %d chunk %d has an invalid delay: %w", i, j, err)
				}
			}
		}
		length := paddingVariantLength(variant)
		if length > maxPaddingTurnLength {
			return 0, 0, fmt.Errorf("variant %d is too long: %d", i, length)
		}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Give every variant at least one chunk of length 1..49152 (maxPaddingChunkLength).
  2. Filter out empty variants before building the schedule.
  3. Add a config-side check: reject padding entries with an empty chunks array at load time.

Example fix

// before
variants = append(variants, paddingVariant{})
// after
variants = append(variants, paddingVariant{chunks: []int{256}})
Defensive patterns

Strategy: validation

Validate before calling

for i, v := range turn.variants {
    if len(v.chunks) == 0 {
        return fmt.Errorf("variant %d empty", i)
    }
}

Prevention

When it happens

Trigger: Appending paddingVariant{} or a variant built from an empty []int to turn.variants; programmatic variant construction where a loop accidentally appends the zero value.

Common situations: Generating variants from user config where an empty chunk list passes through unvalidated; refactoring presets and leaving a placeholder empty variant behind.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/7587e6cef25f03ce. Report an issue: GitHub.