XTLS/Xray-core · error

variants cannot be combined with a length range

Error message

variants cannot be combined with a length range

What it means

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.

Source

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

func defaultPaddingChunks(recordLength, writeChunkLength int) []int {
	chunks := make([]int, 0, (recordLength+writeChunkLength-1)/writeChunkLength)
	for remaining := recordLength; remaining > 0; {
		chunkLength := min(remaining, writeChunkLength)
		chunks = append(chunks, chunkLength)
		remaining -= chunkLength
	}
	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)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Pick one representation: remove minLength/maxLength (leave both 0) when using variants.
  2. Or drop the variants slice and express the turn as a plain length range.
  3. Sanitize config loading to zero out bounds when variants are detected, if configs come from users.

Example fix

// before
turn := paddingTurn{minLength: 64, maxLength: 64, variants: vs}
// after
turn := paddingTurn{variants: vs}
Defensive patterns

Strategy: validation

Validate before calling

if len(turn.variants) > 0 && (turn.minLength != 0 || turn.maxLength != 0) {
    return errors.New("turn declares both variants and a length range")
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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