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
- Read the wrapped message ('invalid range', 'variant N has no chunks', 'invalid send variant index', etc.) to identify the exact field
- Ensure 1 <= minLength <= maxLength <= 8*1024*1024 for range turns, and minLength=maxLength=0 when variants are set
- 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
- 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
- Run schedule validation in unit tests for every shipped profile
- Sanitize converted traffic traces (drop empty variants, clamp lengths)
- Bounds-check sendVariants indices when they come from config
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
- first prefixed padding turn is not client-to-server
- padding turn %d has invalid direction: %d
- padding turn %d combines variants with generated write chunk
- Failed to convert address to Net IP.
- unexpected client IP length
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/d3888501ccb363f8.
Report an issue: GitHub.