JuliusBrussee/caveman · error
cachebench: invalid trace read limits
Error message
cachebench: invalid trace read limits
What it means
Returned by ReadTraceJSONLWithLimits in cacheengine/cachebench/trace.go when the caller-supplied TraceReadLimits fail validation: MaxLineBytes must be >0 and <=512MiB, MaxRecords must be >0 and <=1,000,000, and MaxBodyBytes must be >0 and <=256MiB. The library enforces these ceilings because trace parsing is resource-intensive and unbounded limits would allow memory exhaustion from a malformed or hostile trace file. It is a programmer-error guard, not a data error: the limits struct itself is invalid before any I/O happens.
Source
Thrown at cacheengine/cachebench/trace.go:281
MaxLineBytes int
MaxRecords int
MaxBodyBytes int
}
// DefaultTraceReadLimits supports public-corpus traces while bounding retained memory.
func DefaultTraceReadLimits() TraceReadLimits {
return TraceReadLimits{MaxLineBytes: 96 << 20, MaxRecords: 100_000, MaxBodyBytes: 64 << 20}
}
// ReadTraceJSONL reads trace records using conservative default resource limits.
func ReadTraceJSONL(reader io.Reader) ([]TraceRecord, error) {
return ReadTraceJSONLWithLimits(reader, DefaultTraceReadLimits())
}
// ReadTraceJSONLWithLimits reads strict trace JSONL under explicit resource limits.
func ReadTraceJSONLWithLimits(reader io.Reader, limits TraceReadLimits) ([]TraceRecord, error) {
if limits.MaxLineBytes <= 0 || limits.MaxLineBytes > 512<<20 || limits.MaxRecords <= 0 || limits.MaxRecords > 1_000_000 || limits.MaxBodyBytes <= 0 || limits.MaxBodyBytes > 256<<20 {
return nil, errors.New("cachebench: invalid trace read limits")
}
scanner := bufio.NewScanner(reader)
initial := 64 * 1024
if limits.MaxLineBytes < initial {
initial = limits.MaxLineBytes
}
scanner.Buffer(make([]byte, initial), limits.MaxLineBytes)
seen := map[string]bool{}
var records []TraceRecord
for line := 1; scanner.Scan(); line++ {
raw := bytes.TrimSpace(scanner.Bytes())
if len(raw) == 0 {
continue
}
if len(records) >= limits.MaxRecords {
return nil, fmt.Errorf("cachebench: trace exceeds record limit %d", limits.MaxRecords)
}
if !validUniqueJSONObject(raw) {View on GitHub (pinned to 27d5a3981a)
Solutions
- Call ReadTraceJSONL(reader) instead, which passes DefaultTraceReadLimits() (MaxLineBytes 96MiB, MaxRecords 100k, MaxBodyBytes 64MiB) and is valid by construction
- If custom limits are needed, clamp each field into range before the call: 0 < MaxLineBytes <= 512<<20, 0 < MaxRecords <= 1_000_000, 0 < MaxBodyBytes <= 256<<20
- Log the limits struct values before calling so the offending field is obvious
- If genuinely larger traces must be parsed, split the trace file and process in batches so MaxRecords stays under 1,000,000
Example fix
// before
limits := cachebench.TraceReadLimits{MaxLineBytes: 1 << 30} // only one field set; others are 0
records, err := cachebench.ReadTraceJSONLWithLimits(r, limits)
// after
records, err := cachebench.ReadTraceJSONLWithLimits(r, cachebench.DefaultTraceReadLimits())
// or clamp explicitly:
// limits.MaxRecords = min(max(limits.MaxRecords, 1), 1_000_000) etc. Defensive patterns
Strategy: validation
Validate before calling
func validTraceLimits(l cachebench.TraceReadLimits) bool {
return l.MaxLineBytes > 0 && l.MaxLineBytes <= 512<<20 &&
l.MaxRecords > 0 && l.MaxRecords <= 1_000_000 &&
l.MaxBodyBytes > 0 && l.MaxBodyBytes <= 256<<20
}
if !validTraceLimits(limits) {
return fmt.Errorf("limits out of range: %+v", limits)
}
records, err := cachebench.ReadTraceJSONLWithLimits(r, limits) Try / catch
records, err := cachebench.ReadTraceJSONLWithLimits(r, limits)
if err != nil {
if err.Error() == "cachebench: invalid trace read limits" {
return fmt.Errorf("config bug: trace limits invalid: %+v", limits)
}
return fmt.Errorf("read trace: %w", err)
} Prevention
- Prefer ReadTraceJSONL, which applies validated defaults
- Centralize limit construction in one config-clamping helper instead of scattering literals
- Never map optional config keys straight into TraceReadLimits; unset ints become 0 and fail
When it happens
Trigger: Calling cachebench.ReadTraceJSONLWithLimits(reader, limits) with any field zero/negative, or with MaxLineBytes > 512<<20, MaxRecords > 1_000_000, or MaxBodyBytes > 256<<20. Copying limits from user input or config without clamping, or building a partial struct (Go zero values make unset ints 0, which fails the <=0 check).
Common situations: Setting limits from a YAML/JSON config where a missing key deserializes as 0; passing math.MaxInt to 'disable' a cap; unit tests constructing TraceReadLimits with only one field set; upgrading from an older version that accepted arbitrary limits.
Related errors
- cachebench: no providers
- cache-replay: -trace and positive request/token/trace/respon
- cacheengine: invalid scope
- cacheengine: invalid epoch
- token budget must be positive, zero (default), or UnlimitedT
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/cfd55a51ce20a0d3.
Report an issue: GitHub.