JuliusBrussee/caveman · error

cacheengine: longer prefix cannot have higher expected reuse

Error message

cacheengine: longer prefix cannot have higher expected reuse

What it means

Thrown by breakpointCandidates when expected reuse is not monotonically non-increasing: a longer prefix (more segments) reports strictly more expected calls than the previous shorter prefix. Since every caller of the longer prefix also sees the shorter one, reuse counts physically cannot grow with prefix length — a violation means wrong measurements.

Source

Thrown at cacheengine/engine.go:377

func breakpointCandidates(segments []Segment, defaultCalls int, profile Profile) ([]Breakpoint, bool, bool, error) {
	var candidates []Breakpoint
	var prefix []byte
	cumulativeTokens := 0
	previousCalls := math.MaxInt
	belowMinimum := false
	negative := false
	for index, segment := range segments {
		prefix = appendFrame(prefix, segment.Name, segment.Content)
		if segment.Tokens > math.MaxInt-cumulativeTokens {
			return nil, false, false, errors.New("cacheengine: cumulative token count overflow")
		}
		cumulativeTokens += segment.Tokens
		calls := segment.ExpectedCalls
		if calls == 0 {
			calls = defaultCalls
		}
		if calls > previousCalls {
			return nil, false, false, errors.New("cacheengine: longer prefix cannot have higher expected reuse")
		}
		previousCalls = calls
		if calls < 2 {
			continue
		}
		if cumulativeTokens > 0 && cumulativeTokens < profile.MinPrefixTokens {
			belowMinimum = true
			continue
		}
		net := 0.0
		if cumulativeTokens > 0 && profile.EconomicsKnown {
			rawNet := float64(cumulativeTokens) * (float64(calls) - profile.WriteMultiplier - float64(calls-1)*profile.ReadMultiplier)
			if math.IsNaN(rawNet) || math.IsInf(rawNet, 0) {
				return nil, false, false, errors.New("cacheengine: cache economics overflow")
			}
			net = roundUnits(rawNet)
			if net <= 0 {
				negative = true

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Compute ExpectedCalls as non-increasing over the segment list (it is a property of nested prefixes — cap later values at the earlier ones)
  2. Pass a defaultCalls value no larger than the smallest explicit ExpectedCalls in the list, or set explicit values everywhere
  3. Order segments so the most-reused, most-stable content is first

Example fix

// before
segments := []cacheengine.Segment{
    {Name: "sys", Stable: true, Cacheable: true, Content: sys, Tokens: 900, ExpectedCalls: 3},
    {Name: "docs", Stable: true, Cacheable: true, Content: docs, Tokens: 5000, ExpectedCalls: 8},
}

// after
segments := []cacheengine.Segment{
    {Name: "sys", Stable: true, Cacheable: true, Content: sys, Tokens: 900, ExpectedCalls: 8},
    {Name: "docs", Stable: true, Cacheable: true, Content: docs, Tokens: 5000, ExpectedCalls: 3},
}
Defensive patterns

Strategy: validation

Validate before calling

func monotonicCalls(segs []cacheengine.Segment, def int) error {
    prev := math.MaxInt
    for _, s := range segs {
        c := s.ExpectedCalls
        if c == 0 { c = def }
        if c > prev { return errors.New("expected calls must be non-increasing") }
        prev = c
    }
    return nil
}

Type guard

// n/a

Prevention

When it happens

Trigger: Setting ExpectedCalls per segment such that a later segment in the list has a higher value (after substituting defaultCalls for 0) than any earlier one, e.g. segments [10, 5, 8] or [3, 0(default=100)] where the default exceeds the earlier explicit value.

Common situations: Per-segment analytics counting events instead of prefix-sharing callers; mixing a small explicit ExpectedCalls on an early segment with a zero (defaulted) value on a later one where defaultCalls is larger; ordering segments by recency instead of by prefix stability so counts grow down the list.

Related errors


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