XTLS/Xray-core · critical
`scMaxEachPostBytes` should be bigger than 0
Error message
`scMaxEachPostBytes` should be bigger than 0
What it means
The splithttp dialer panics because GetNormalizedScMaxEachPostBytes().From is <= 0 after normalization. Normalization only substitutes defaults when ScMaxEachPostBytes is nil or To == 0; a RangeConfig explicitly present with From <= 0 (or To set but From unset/negative) reaches this check and kills the process at stream-dial time. scMaxEachPostBytes caps the size of each POST upload chunk in stream-up (XHTTP) mode.
Source
Thrown at transport/internet/splithttp/dialer.go:487
return nil, err
}
}
if mode == "stream-up" {
if xmuxClient != nil {
xmuxClient.LeftRequests.Add(-1)
}
_, _, _, err = httpClient.OpenStream(ctx, requestURL.String(), sessionId, reader, true)
if err != nil { // browser dialer only
return nil, err
}
return stat.Connection(&conn), nil
}
scMaxEachPostBytes := transportConfiguration.GetNormalizedScMaxEachPostBytes()
scMinPostsIntervalMs := transportConfiguration.GetNormalizedScMinPostsIntervalMs()
if scMaxEachPostBytes.From <= 0 {
panic("`scMaxEachPostBytes` should be bigger than 0")
}
maxUploadSize := scMaxEachPostBytes.rand()
// WithSizeLimit(0) will still allow single bytes to pass, and a lot of
// code relies on this behavior. Subtract 1 so that together with
// uploadWriter wrapper, exact size limits can be enforced
// uploadPipeReader, uploadPipeWriter := pipe.New(pipe.WithSizeLimit(maxUploadSize - 1))
uploadPipeReader, uploadPipeWriter := pipe.New(pipe.WithSizeLimit(max(0, maxUploadSize-buf.Size)))
conn.writer = uploadWriter{
uploadPipeWriter,
maxUploadSize,
}
go func() {
var seq int64
var lastWrite time.Time
View on GitHub (pinned to 7d214f8b09)
Solutions
- Set both bounds positive, e.g. {"from": 1000000, "to": 2000000}, or remove the scMaxEachPostBytes block entirely to take the built-in defaults.
- If you only care about a cap, keep From equal to a sane floor (e.g. 1–2 MB) — From drives the random upload-chunk size lower bound and must be >= 1.
- Fix config generators to omit the field rather than emit {from:0,to:0}.
Example fix
// before (config.json splithttp settings)
"scMaxEachPostBytes": { "to": 2000000 }
// after
"scMaxEachPostBytes": { "from": 1000000, "to": 2000000 } Defensive patterns
Strategy: validation
Validate before calling
if c.ScMaxEachPostBytes != nil && (c.ScMaxEachPostBytes.From <= 0 || c.ScMaxEachPostBytes.To < c.ScMaxEachPostBytes.From) {
return errors.New("scMaxEachPostBytes must satisfy 0 < from <= to")
} Prevention
- Always set both from and to to positive values, or omit scMaxEachPostBytes to use defaults.
- Omit the field rather than emitting {from:0,to:0} in generated configs (proto3 zero values).
- Check the effective normalized values in a startup log line while debugging upload issues.
When it happens
Trigger: Explicitly setting "scMaxEachPostBytes": {"from": 0} or {"to": N} without a positive "from" in the splithttp transport config; negative values; configs generated programmatically that zero the From field while keeping To.
Common situations: Hand-written JSON where only "to" is set because authors assume from is optional; migrating from configs where the field was a plain integer; tools that emit 0 for unset numeric fields (proto3 default) combined with a non-zero To.
Related errors
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/5b2e08abf7e338ea.
Report an issue: GitHub.