JuliusBrussee/caveman · error

cacheengine: stable prefix exceeds configured byte limit

Error message

cacheengine: stable prefix exceeds configured byte limit

What it means

Thrown by stablePrefix when the framed prefix cannot fit in maxBytes: the limit itself is below 8 (framing header size), or name+content of the current segment, or the accumulated prefix plus the segment, would exceed maxBytes-8. Each segment costs 8 bytes of length framing plus name plus content.

Source

Thrown at cacheengine/engine.go:339

}

func stablePrefix(segments []Segment, maxBytes int) ([]byte, []Segment, error) {
	var prefix []byte
	var stable []Segment
	seenNames := map[string]bool{}
	for _, segment := range segments {
		if !segment.Stable || !segment.Cacheable {
			break
		}
		if !validIdentity(segment.Name, 1024, false) || len(segment.Content) == 0 || seenNames[segment.Name] {
			return nil, nil, errors.New("cacheengine: stable segment needs name and content")
		}
		seenNames[segment.Name] = true
		if segment.Tokens < 0 || segment.ExpectedCalls < 0 {
			return nil, nil, errors.New("cacheengine: negative segment measurement")
		}
		if maxBytes < 8 || len(segment.Name) > maxBytes-8 || len(segment.Content) > maxBytes-8-len(segment.Name) || len(prefix) > maxBytes-8-len(segment.Name)-len(segment.Content) {
			return nil, nil, errors.New("cacheengine: stable prefix exceeds configured byte limit")
		}
		if len(segment.Name) > math.MaxUint32 || len(segment.Content) > math.MaxUint32 {
			return nil, nil, errors.New("cacheengine: segment exceeds framing limit")
		}
		prefix = appendFrame(prefix, segment.Name, segment.Content)
		stable = append(stable, segment)
	}
	return prefix, stable, nil
}

func appendFrame(dst []byte, name string, content []byte) []byte {
	var lengths [8]byte
	binary.BigEndian.PutUint32(lengths[:4], uint32(len(name)))
	binary.BigEndian.PutUint32(lengths[4:], uint32(len(content)))
	dst = append(dst, lengths[:]...)
	dst = append(dst, name...)
	return append(dst, content...)
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Raise the configured maxBytes to fit the full stable prefix (remember +8 framing bytes per segment)
  2. Trim or shrink stable segment content (fewer/fresher documents) so the framed prefix fits
  3. If maxBytes < 8 in your config, it is invalid for any use — fix the configuration value

Example fix

// before
engine := cacheengine.New(cfg) // cfg.MaxPrefixBytes left at 0 -> any stable segment fails

// after
cfg.MaxPrefixBytes = 64 * 1024 // comfortably above sum(len(name)+len(content)+8) of all stable segments
engine := cacheengine.New(cfg)
Defensive patterns

Strategy: validation

Validate before calling

func framedPrefixSize(segs []cacheengine.Segment) int {
    n := 0
    for _, s := range segs {
        if !s.Stable || !s.Cacheable { break }
        n += 8 + len(s.Name) + len(s.Content)
    }
    return n
}
// require framedPrefixSize(segs) <= cfg.MaxPrefixBytes && cfg.MaxPrefixBytes >= 8

Type guard

// n/a

Prevention

When it happens

Trigger: Calling Plan with a small configured byte limit (or 0/unset) while stable segments are large; growing the stable prefix segment-by-segment until the cumulative framed size passes the configured cap; maxBytes < 8 makes every input fail.

Common situations: Forgetting to configure the byte limit so it defaults to something tiny (or zero); raising prompt content without raising the provider prefix limit; adding another stable document block to a prefix already near the cap.

Related errors


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