JuliusBrussee/caveman · error
cachebench: replay preparation interrupted: %w
Error message
cachebench: replay preparation interrupted: %w
What it means
The context passed to ReplayRunner.prepare was canceled or expired while it was looping over trace records preparing optimized bodies. Preparation checks ctx.Err() between records and wraps it with this message, so no partial results are used.
Source
Thrown at cacheengine/cachebench/replay.go:505
}
anchorTrace, _ := time.Parse(time.RFC3339Nano, records[0].At)
anchorReal := now().UTC()
if runner.Limits.MaxConcurrency == 1 {
return runner.runSequential(ctx, prepared, anchorTrace, anchorReal, now, sleep, emit)
}
return runner.runConcurrent(ctx, prepared, anchorTrace, anchorReal, now, sleep, emit)
}
type preparedReplay struct {
record TraceRecord
optimized cacheengine.NativeResult
}
func (runner ReplayRunner) prepare(ctx context.Context, records []TraceRecord) ([]preparedReplay, error) {
prepared := make([]preparedReplay, 0, len(records))
for _, record := range records {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("cachebench: replay preparation interrupted: %w", err)
}
native, err := record.NativeRequest()
if err != nil {
return nil, err
}
optimized, err := runner.Engine.Optimize(ctx, native)
if err != nil {
return nil, fmt.Errorf("cachebench: optimize request %q: %w", record.RequestID, err)
}
equivalent := bytes.Equal(native.Body, optimized.Body)
if optimized.Applied {
equivalent = ModelVisibleEquivalent(native.Body, optimized.Body)
}
if !equivalent {
return nil, &ReplayRunError{
RequestID: record.RequestID, FailureCode: "model_visible_mismatch",
Err: fmt.Errorf("cachebench: request %q failed model-visible equivalence", record.RequestID),
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Check what canceled the context: errors.Is(err, context.DeadlineExceeded) vs context.Canceled tells you timeout vs explicit cancel.
- Raise or remove the deadline on the Run/prepare context for large traces.
- If cancellation was intentional (Ctrl+C, shutdown), treat this as a clean abort and discard partial state.
- Speed up preparation (fewer records, faster Engine) so the window for cancellation shrinks.
Example fix
// before ctx, cancel := context.WithTimeout(ctx, 5*time.Second) // prepare of 10k records exceeds it // after ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) defer cancel()
Defensive patterns
Strategy: try-catch
Validate before calling
if err := ctx.Err(); err != nil {
return fmt.Errorf("refusing to start replay: %w", err)
} Try / catch
if err := runner.Run(ctx, records, emit); err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
// treat as aborted run; persist already-emitted results and exit cleanly
}
return err
} Prevention
- Size context deadlines to trace length divided by TimeScale, with headroom.
- Cancel the run context only via your shutdown signal, and defer cancel() until after Run returns.
- Estimate prepare cost (records x per-record Optimize latency) before choosing a timeout.
When it happens
Trigger: Canceling the parent context (ctx cancel, timeout on the Run call) while prepare is iterating records; a deadline shorter than the time Engine.Optimize needs for the whole trace; SIGINT handlers that cancel the run context.
Common situations: A command wrapper with a --timeout flag that fires during long replays; test code with context.WithTimeout too tight for large traces; user Ctrl+C mid-run propagating a cancel.
Related errors
- cachebench: replay schedule interrupted: %w
- cachebench: session %q request %d: %w
- cachebench: observation request %q body digest mismatch
- cachebench: replay request %q has empty provider
- cachebench: provider %q population %d cannot meet minimum el
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/706f203d89785676.
Report an issue: GitHub.