JuliusBrussee/caveman · error · ReplayRunError

transport_error

transport_error

Error message

cachebench: provider transport failed for %q: %w

What it means

Transport.Send returned a non-nil error while delivering the optimized request. The runner still records HTTP status and response body digest into evidence, then fails the request with FailureCode transport_error wrapping the transport error.

Source

Thrown at cacheengine/cachebench/replay.go:695

	evidence.HTTPStatus = response.StatusCode
	if len(response.Body) > 0 {
		evidence.ProviderEvidenceSHA256 = bodyDigest(response.Body)
	}
	if completed.Before(started) {
		evidence.CompletedAt = started.Format(time.RFC3339Nano)
		evidence.FailureCode = "clock_regression"
		return ReplayResult{Evidence: evidence, ProviderResponse: append([]byte(nil), response.Body...)}, &ReplayRunError{
			RequestID: record.RequestID, FailureCode: evidence.FailureCode,
			Err: fmt.Errorf("cachebench: clock regressed while replaying %q", record.RequestID),
		}
	}
	evidence.CompletedAt = completed.Format(time.RFC3339Nano)
	evidence.LatencyMilliseconds = completed.Sub(started).Milliseconds()
	if sendErr != nil {
		evidence.FailureCode = "transport_error"
		return ReplayResult{Evidence: evidence, ProviderResponse: append([]byte(nil), response.Body...)}, &ReplayRunError{
			RequestID: record.RequestID, FailureCode: evidence.FailureCode,
			Err: fmt.Errorf("cachebench: provider transport failed for %q: %w", record.RequestID, sendErr),
		}
	}
	if !validProviderRequestID(response.ProviderRequestID) {
		evidence.FailureCode = "provider_response_invalid"
		return ReplayResult{Evidence: evidence, ProviderResponse: append([]byte(nil), response.Body...)}, &ReplayRunError{
			RequestID: record.RequestID, FailureCode: evidence.FailureCode,
			Err: fmt.Errorf("cachebench: provider returned invalid request identity for %q", record.RequestID),
		}
	}
	evidence.ProviderRequestID = response.ProviderRequestID
	if response.StatusCode < 200 || response.StatusCode >= 300 {
		evidence.FailureCode = "provider_http_status"
		return ReplayResult{Evidence: evidence, ProviderResponse: append([]byte(nil), response.Body...)}, &ReplayRunError{
			RequestID: record.RequestID, FailureCode: evidence.FailureCode,
			Err: fmt.Errorf("cachebench: provider returned HTTP %d for %q", response.StatusCode, record.RequestID),
		}
	}
	usage, ok := cacheengine.ExtractProviderUsage(record.Provider, response.Body)

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Unwrap and inspect the underlying error (%w) — it distinguishes DNS/TLS/auth/deadline causes.
  2. Verify network egress, proxy settings, and credentials for the endpoint in the trace record.
  3. Retry the replay: transient network errors are the most common cause, and replay is idempotent from the harness side.
  4. If context.DeadlineExceeded, raise the per-run or transport timeout.

Example fix

// before
err := runner.Run(ctx, records, emit) // fails: dial tcp: i/o timeout

// after
// fix egress/proxy, e.g.
transport := cachebench.NewHTTPTransport(cachebench.HTTPTransportConfig{Proxy: os.Getenv("HTTPS_PROXY"), Timeout: 120 * time.Second})
err := runner.Run(ctx, records, emit)
Defensive patterns

Strategy: retry

Validate before calling

// probe endpoint reachability before the run
if err := transport.HealthCheck(ctx, endpoint); err != nil {
    return fmt.Errorf("transport not ready: %w", err)
}

Type guard

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

Try / catch

if err := runner.Run(ctx, records, emit); err != nil {
    if isTransportError(err) {
        cause := errors.Unwrap(err)
        if isTransient(cause) { // net errors, TLS reset, 429-bearing transport errors
            // fix network/credentials if not transient; otherwise re-run the replay
        }
    }
    return err
}

Prevention

When it happens

Trigger: Network failures to the provider endpoint (DNS, refused connection, TLS), context cancellation during send, proxy misconfiguration, or an overloaded provider closing connections. Any error from the injected Transport implementation lands here.

Common situations: Replaying against a provider API from a sandbox without egress; expired API credentials causing the transport's own error; corporate proxy required but not configured; context deadline hit during a slow streaming response.

Related errors


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