JuliusBrussee/caveman · error
cachebench: no trace records
Error message
cachebench: no trace records
What it means
Returned by ReadTraceJSONLWithLimits when the scanner reached EOF without accumulating any records. Every line was either empty after bytes.TrimSpace or the input was empty entirely, so the parsed record slice has length 0. The library treats a record-less trace as an error because downstream replay/validation code assumes at least one trace record exists.
Source
Thrown at cacheengine/cachebench/trace.go:342
if record.Schema == TraceSchema || record.Schema == TraceSchemaV2 {
if record.ExpectedRPM <= 0 || record.ExpectedCalls <= 0 || !validTimingBasis(record.TimingBasis) {
return nil, fmt.Errorf("cachebench: trace line %d: incomplete replay metadata", line)
}
}
if record.Schema == TraceSchema {
if record.DeclaredInputTokens <= 0 || record.DeclaredInputTokens < record.PrefixTokens || record.MaxOutputTokens <= 0 || !requestBudgetMatchesBody(record) {
return nil, fmt.Errorf("cachebench: trace line %d: incomplete or mismatched billed-token budget", line)
}
}
seen[record.RequestID] = true
record.Body = append(json.RawMessage(nil), record.Body...)
records = append(records, record)
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("cachebench: read trace: %w", err)
}
if len(records) == 0 {
return nil, errors.New("cachebench: no trace records")
}
return records, nil
}
// NativeRequest reconstructs exact optimizer input captured by v2 or v3 trace.
// Legacy v1 traces remain readable for observation joins, but cannot drive live
// replay because they omitted routing and economics inputs.
func (record TraceRecord) NativeRequest() (cacheengine.NativeRequest, error) {
if record.Schema != TraceSchema && record.Schema != TraceSchemaV2 {
return cacheengine.NativeRequest{}, fmt.Errorf("cachebench: request %q needs %s or %s for reconstruction", record.RequestID, TraceSchemaV2, TraceSchema)
}
if !validTraceIdentity(record) || !validTimingBasis(record.TimingBasis) || record.ExpectedRPM <= 0 || record.ExpectedCalls <= 0 || record.PrefixTokens < 0 || !validUniqueJSONObject(record.Body) || record.BodySHA256 != bodyDigest(record.Body) || record.StableSegmentCount < 0 || record.StableSegmentCount > len(record.Prefix) || !validPrefix(record.Prefix) {
return cacheengine.NativeRequest{}, fmt.Errorf("cachebench: request %q has incomplete or invalid replay identity", record.RequestID)
}
return cacheengine.NativeRequest{
Scope: record.Scope, Epoch: record.Epoch, PartitionKey: record.PartitionKey,
ExpectedRequestsPerMinute: record.ExpectedRPM, ExpectedCalls: record.ExpectedCalls,
Provider: record.Provider, Model: record.Model, Region: record.Region, Endpoint: record.Endpoint,View on GitHub (pinned to 27d5a3981a)
Solutions
- Verify the trace file is non-empty and contains JSONL lines before parsing: check file size and first non-blank line
- If the file is unexpectedly empty, re-run the trace capture step that produced it
- Guard callers that legitimately may have no data by checking len(records)==0 upstream and skipping the parse entirely
Example fix
// before
records, err := cachebench.ReadTraceJSONL(f) // f is empty -> error
// after
info, _ := f.Stat()
if info.Size() == 0 {
return fmt.Errorf("trace file %s is empty; regenerate it", path)
}
records, err := cachebench.ReadTraceJSONL(f) Defensive patterns
Strategy: validation
Validate before calling
info, err := f.Stat()
if err != nil {
return err
}
if info.Size() == 0 {
return errors.New("trace file is empty; skipping parse")
}
records, err := cachebench.ReadTraceJSONL(f) Try / catch
records, err := cachebench.ReadTraceJSONL(r)
if err != nil {
if strings.Contains(err.Error(), "no trace records") {
log.Print("empty trace; nothing to replay")
return nil, nil
}
return nil, err
} Prevention
- Make trace producers write atomically (temp file + rename) so failed captures leave no empty artifacts
- Assert non-zero size when downloading/receiving traces in CI before invoking replay
When it happens
Trigger: Passing an empty io.Reader or a file containing only whitespace/newlines to ReadTraceJSONL or ReadTraceJSONLWithLimits. Pointing -trace at a zero-byte file or a file whose lines are all blank. Passing an os.File opened on a path that was truncated by a previous failed write.
Common situations: Trace capture job failed midway and left an empty file; CI pipeline passes an artifact path before the artifact is downloaded; shell redirect typo created an empty file (e.g. '> trace.jsonl' run without the producing command); passing bytes.NewReader(nil) in tests.
Related errors
- cachebench: invalid corpus
- cave_eve_terminal_${result.status}
- cave_harness_upstream_version_mismatch
- cave_mastra_max_steps_invalid
- cave_claude_header_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/8e840a339c6aa5ec.
Report an issue: GitHub.