JuliusBrussee/caveman · error · ReplayRunError

engine_not_cacheable

engine_not_cacheable

Error message

cachebench: request %q is not cacheable: %s

What it means

After optimization, the record's Decision is neither DecisionApply nor DecisionObserveOnly, and its Reason is not ReasonBelowMinimum — the engine judged the request not cache-eligible for some other reason. The replay gate requires every prepared request to be cacheable (or explicitly below the minimum-size threshold), so preparation fails with FailureCode engine_not_cacheable and the engine's reason string.

Source

Thrown at cacheengine/cachebench/replay.go:528

		}
		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),
			}
		}
		if optimized.Decision != cacheengine.DecisionApply && optimized.Decision != cacheengine.DecisionObserveOnly && optimized.Reason != cacheengine.ReasonBelowMinimum {
			return nil, &ReplayRunError{
				RequestID: record.RequestID, FailureCode: "engine_not_cacheable",
				Err: fmt.Errorf("cachebench: request %q is not cacheable: %s", record.RequestID, optimized.Reason),
			}
		}
		prepared = append(prepared, preparedReplay{record: record, optimized: optimized})
	}
	return prepared, nil
}

func validatePreparedReplayTarget(prepared []preparedReplay, target Target) error {
	if err := validateTarget(target); err != nil {
		return err
	}
	providers := map[string]bool{}
	eligible := map[string]int{}
	for _, item := range prepared {
		provider := strings.ToLower(strings.TrimSpace(item.record.Provider))
		providers[provider] = true
		if item.optimized.Decision == cacheengine.DecisionApply || item.optimized.Decision == cacheengine.DecisionObserveOnly {
			eligible[provider]++

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Read the %s reason in the message — it is the engine's own rejection text for that request.
  2. Filter the trace before replay to requests the engine deems cacheable (dry-run Optimize per record and keep Decision Apply/ObserveOnly or Reason BelowMinimum).
  3. Loosen engine eligibility rules if the rejected class of requests should be cacheable.
  4. Re-check populations after filtering, or error 886 (eligible minimum) will fire next.

Example fix

// before
err := runner.Run(ctx, allRecords, emit) // trace contains non-cacheable rows

// after
var cacheable []cachebench.TraceRecord
for _, r := range allRecords {
    if ok, _ := engineEligible(ctx, engine, r); ok { cacheable = append(cacheable, r) }
}
err := runner.Run(ctx, cacheable, emit)
Defensive patterns

Strategy: validation

Validate before calling

var keep []cachebench.TraceRecord
for _, r := range records {
    native, err := r.NativeRequest()
    if err != nil { continue }
    opt, err := engine.Optimize(ctx, native)
    if err != nil { continue }
    if opt.Decision == cacheengine.DecisionApply || opt.Decision == cacheengine.DecisionObserveOnly || opt.Reason == cacheengine.ReasonBelowMinimum {
        keep = append(keep, r)
    }
}
records = keep

Type guard

func isEngineNotCacheable(err error) bool {
    var rre *cachebench.ReplayRunError
    return errors.As(err, &rre) && rre.FailureCode == "engine_not_cacheable"
}

Try / catch

if err := runner.Run(ctx, records, emit); err != nil {
    if isEngineNotCacheable(err) {
        // read the reason string; filter trace or relax engine rules, then retry
    }
    return err
}

Prevention

When it happens

Trigger: A trace containing requests the engine refuses to cache: unsupported endpoints, non-cacheable content types, streaming-only requests, or any engine-specific rejection reason surfaced via optimized.Reason.

Common situations: Replaying a production trace that includes mixed workloads (some cache-ineligible) against strict engine rules; engine rules tightened between capture and replay; a new endpoint not yet whitelisted as cacheable.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/e0712401ee66766f. Report an issue: GitHub.