XTLS/Xray-core · error
padding turn %d has an invalid chunk delay: %w
Error message
padding turn %d has an invalid chunk delay: %w
What it means
validatePaddingSchedule rejected turn i's chunkDelay range: min negative or max < min. Chunk delays space out individual padding chunk writes inside a turn and must satisfy 0 <= min <= max, same rule as start delays.
Source
Thrown at transport/internet/finalmask/xmc/padding.go:92
if len(schedule) == 0 {
return fmt.Errorf("empty padding schedule")
}
if firstTurnPrefixLength < 0 {
return fmt.Errorf("negative first turn prefix length: %d", firstTurnPrefixLength)
}
if firstTurnPrefixLength > 0 && schedule[0].direction != paddingClientToServer {
return fmt.Errorf("first prefixed padding turn is not client-to-server")
}
for i, turn := range schedule {
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 {View on GitHub (pinned to 7d214f8b09)
Solutions
- Fix the range so 0 <= chunkDelay.min <= chunkDelay.max
- Validate delay ranges at config-load time when they are externally configurable
- Add a helper that constructs paddingDelayRange and rejects inverted inputs
Example fix
// before
chunkDelay: paddingDelayRange{min: -time.Millisecond, max: time.Second}
// after
chunkDelay: paddingDelayRange{min: 0, max: time.Second} Defensive patterns
Strategy: validation
Validate before calling
func validChunkDelay(d paddingDelayRange) bool { return d.min >= 0 && d.max >= d.min } Prevention
- Construct delay ranges through one helper that rejects inverted inputs
- Validate config-sourced delays before building turns
When it happens
Trigger: A schedule turn with chunkDelay.min negative or fields ordered max-then-min swapped in a struct literal.
Common situations: Config-driven delays with signed values; copy-paste between startDelay and chunkDelay fields with wrong ordering; tests with sentinel durations.
Related errors
- padding turn %d has an invalid start delay: %w
- empty padding schedule
- negative first turn prefix length: %d
- first prefixed padding turn is not client-to-server
- padding turn %d has invalid direction: %d
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/94bfcdf7ced7374f.
Report an issue: GitHub.