XTLS/Xray-core · error

padding turn %d: %w

Error message

padding turn %d: %w

What it means

validatePaddingSchedule wrapped a paddingTurnBounds failure for turn i: either an invalid min/max length range (min < 1, max < min, or max > 8 MiB), variants combined with a non-zero length range, a variant with no chunks, chunk/delay count mismatch, an invalid variant chunk length or delay, an over-long variant, or an out-of-range sendVariants index.

Source

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

		if turn.direction != paddingClientToServer && turn.direction != paddingServerToClient {
			return fmt.Errorf("padding turn %d has invalid direction: %d", i, turn.direction)
		}
		if err := validatePaddingDelayRange(turn.startDelay); err != nil {
			return fmt.Errorf("padding turn %d has an invalid start delay: %w", i, err)
		}
		if err := validatePaddingDelayRange(turn.chunkDelay); err != nil {
			return fmt.Errorf("padding turn %d has an invalid chunk delay: %w", i, err)
		}
		if turn.writeChunkMinLength < 0 || turn.writeChunkLength < turn.writeChunkMinLength || turn.writeChunkLength > maxPaddingChunkLength {
			return fmt.Errorf("padding turn %d has an invalid write chunk range: %d-%d", i, turn.writeChunkMinLength, turn.writeChunkLength)
		}
		if len(turn.variants) > 0 && turn.writeChunkLength != 0 {
			return fmt.Errorf("padding turn %d combines variants with generated write chunks", i)
		}

		minLength, maxLength, err := paddingTurnBounds(turn)
		if err != nil {
			return fmt.Errorf("padding turn %d: %w", i, err)
		}
		hasSendRange := turn.sendMinLength != 0 || turn.sendMaxLength != 0
		if hasSendRange {
			if len(turn.variants) > 0 {
				return fmt.Errorf("padding turn %d combines variants with a send range", i)
			}
			if turn.sendMinLength < minLength || turn.sendMaxLength < turn.sendMinLength || turn.sendMaxLength > maxLength {
				return fmt.Errorf("padding turn %d has an invalid send range: %d-%d", i, turn.sendMinLength, turn.sendMaxLength)
			}
		}
		if i == 0 && minLength-firstTurnPrefixLength < 1 {
			return fmt.Errorf("padding turn 0 is too short for %d prefix bytes", firstTurnPrefixLength)
		}
		if i == 0 && len(turn.variants) > 0 {
			for j, variant := range turn.variants {
				if _, _, err = trimPaddingPrefix(variant, firstTurnPrefixLength); err != nil {
					return fmt.Errorf("padding turn 0 variant %d: %w", j, err)
				}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Read the wrapped message ('invalid range', 'variant N has no chunks', 'invalid send variant index', etc.) to identify the exact field
  2. Ensure 1 <= minLength <= maxLength <= 8*1024*1024 for range turns, and minLength=maxLength=0 when variants are set
  3. Give every variant at least one chunk, delays arrays of length 0 or equal to chunks, chunk lengths in 1..48 KiB, and sendVariants indices within range
  4. Validate schedules in unit tests before shipping them

Example fix

// before
turn := paddingTurn{variants: vs, minLength: 100, maxLength: 200}

// after
turn := paddingTurn{variants: vs} // range must be unset when variants present
Defensive patterns

Strategy: validation

Validate before calling

func validTurnBounds(turn paddingTurn) bool {
    if len(turn.variants) == 0 {
        return turn.minLength >= 1 && turn.maxLength >= turn.minLength && turn.maxLength <= 8*1024*1024
    }
    if turn.minLength != 0 || turn.maxLength != 0 {
        return false
    }
    for _, v := range turn.variants {
        if len(v.chunks) == 0 {
            return false
        }
        if len(v.delays) != 0 && len(v.delays) != len(v.chunks) {
            return false
        }
        for _, c := range v.chunks {
            if c < 1 || c > 48*1024 {
                return false
            }
        }
    }
    for _, i := range turn.sendVariants {
        if i < 0 || i >= len(turn.variants) {
            return false
        }
    }
    return true
}

Prevention

When it happens

Trigger: Hand-written or generated turns with minLength 0, ranges exceeding maxPaddingTurnLength (8 MiB), variant structs with empty chunks or delays arrays shorter than chunks, or sendVariants referencing nonexistent variant indices.

Common situations: Forks authoring new traffic-shape profiles; converting captured traffic traces into variants and dropping empty entries; config-driven schedules with unvalidated indices.

Related errors


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