JuliusBrussee/caveman · error

cacheengine: stable segment needs name and content

Error message

cacheengine: stable segment needs name and content

What it means

Thrown by stablePrefix while folding the leading run of Stable && Cacheable segments: a segment must have a valid non-empty Name (<= 1024 bytes, identity rules), non-empty Content, and a Name not seen earlier in the prefix. The loop stops at the first non-stable/non-cacheable segment, so only the head of the segment list is affected.

Source

Thrown at cacheengine/engine.go:332

	if profile.MaxRPMPerKey == 0 {
		profile.MaxRPMPerKey = 15
	}
	if profile.Attribution == "" {
		profile.Attribution = AttributionNone
	}
	return profile
}

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 {

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Give every stable cacheable segment a unique, non-empty, <= 1024-byte identity-safe Name
  2. Ensure Content is non-empty for each stable segment (skip the segment instead of sending it empty)
  3. Deduplicate names by indexing them (e.g. 'context-1', 'context-2') if you legitimately repeat a kind of segment

Example fix

// before
segments := []cacheengine.Segment{{Name: "docs", Stable: true, Cacheable: true, Content: nil}}

// after
segments := []cacheengine.Segment{{Name: "docs-v2", Stable: true, Cacheable: true, Content: docBytes}}
Defensive patterns

Strategy: validation

Validate before calling

func stableSegmentsOK(segs []cacheengine.Segment) error {
    seen := map[string]bool{}
    for _, s := range segs {
        if !s.Stable || !s.Cacheable { break }
        if s.Name == "" || len(s.Name) > 1024 || len(s.Content) == 0 || seen[s.Name] { return fmt.Errorf("bad segment %q", s.Name) }
        seen[s.Name] = true
    }
    return nil
}

Type guard

func isStableSegment(s cacheengine.Segment) bool { return s.Stable && s.Cacheable && s.Name != "" && len(s.Content) > 0 }

Prevention

When it happens

Trigger: Passing Segments where a leading stable/cacheable segment has Name == "" (or > 1024 bytes / bad charset), Content of zero length, or two leading stable segments sharing the same Name.

Common situations: Generating segment names from user content that can be empty; reusing a constant name like 'context' for multiple stable segments; forgetting that the system/description segment must carry content; whitespace-trimmed content becoming empty.

Related errors


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