XTLS/Xray-core · error
read padding turn %d: %w
Error message
read padding turn %d: %w
What it means
runPaddingSchedule failed while reading the peer's padding turn i: the record length header could not be read, the length was implausible (<header size or >8 MiB), the total fell outside the turn's accepted range/variant set, or the body read hit EOF. In practice this means the peer's padding does not match what this side expects.
Source
Thrown at transport/internet/finalmask/xmc/padding.go:67
return err
}
var writeBuffer []byte
for i, turn := range schedule {
prefixLength := 0
if i == 0 {
prefixLength = firstTurnPrefixLength
}
localSends := isClient == (turn.direction == paddingClientToServer)
if localSends {
if err := writePaddingTurnWithBuffer(writer, turn, prefixLength, time.Sleep, &writeBuffer); err != nil {
return fmt.Errorf("write padding turn %d: %w", i, err)
}
continue
}
if err := readPaddingTurn(reader, turn, prefixLength); err != nil {
return fmt.Errorf("read padding turn %d: %w", i, err)
}
}
return nil
}
func validatePaddingSchedule(schedule []paddingTurn, firstTurnPrefixLength int) error {
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 {View on GitHub (pinned to 7d214f8b09)
Solutions
- Confirm both ends run the same xmc version so padding schedules match
- Verify the remote address is the xmc counterpart, not a vanilla Minecraft or HTTP server
- Check for full-stream connectivity (the wrapped error often is a read timeout or EOF)
- Treat as fatal: close the connection and retry the dial
Defensive patterns
Strategy: try-catch
Try / catch
err := runPaddingSchedule(...)
if err != nil && strings.Contains(err.Error(), "read padding turn") {
// peer padding mismatch: wrong version or wrong endpoint; abort dial
return err
} Prevention
- Match xmc versions on client and server
- Health-check the remote endpoint before relying on the tunnel
- Retain packet captures of the padding phase to debug schedule mismatches
When it happens
Trigger: Client and server padding schedules differ (version mismatch); peer is not an xmc endpoint so its bytes are not padding records; connection drops mid-padding so readPaddingTurn gets EOF/partial data.
Common situations: Mixing library versions where newClientPaddingSchedule2612 changed; pointing the transport at a real Minecraft server or random service; middlebox truncating the handshake; test harnesses feeding arbitrary bytes.
Related errors
- write padding turn %d: %w
- run startup padding: %w
- write encryption response: %w
- read login finished: %w
- write login acknowledged: %w
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/a7f0a2493f935967.
Report an issue: GitHub.