JuliusBrussee/caveman · error
cachebench: invalid stable identity boundary
Error message
cachebench: invalid stable identity boundary
What it means
corpusStableIdentity clamps a zero stableCount to 1 but rejects stableCount greater than the number of messages: the stable prefix must be a real leading slice of the conversation. A boundary past the end means the caller's notion of prefix length disagrees with the actual session length.
Source
Thrown at cacheengine/cachebench/corpus.go:698
}
sort.SliceStable(requests, func(i, j int) bool { return requests[i].At.Before(requests[j].At) })
return Trace{
Provider: provider,
Scenario: Scenario{Name: corpus.Metadata.Name, Turns: len(requests), AssumedTTL: 5 * time.Minute, Step: time.Second},
Requests: requests, TokenBasis: counter.Name() + " estimate over normalized OpenAI messages",
TimingBasis: TimingPerPartition,
}, nil
}
func corpusStableIdentity(messages []CorpusMessage, stableCount int) (string, error) {
if len(messages) == 0 {
return "", errors.New("cachebench: empty stable identity")
}
if stableCount == 0 {
stableCount = 1
}
if stableCount > len(messages) {
return "", errors.New("cachebench: invalid stable identity boundary")
}
digest := sha256.New()
encoder := json.NewEncoder(digest)
encoder.SetEscapeHTML(false)
for _, message := range messages[:stableCount] {
if err := encoder.Encode(message); err != nil {
return "", err
}
}
return hex.EncodeToString(digest.Sum(nil)), nil
}
func corpusProviderBody(provider ProviderConfig, messages []CorpusMessage) ([]byte, error) {
switch provider.Provider {
case "openai":
return json.Marshal(map[string]any{"model": provider.Model, "max_completion_tokens": 256, "messages": messages})
case "anthropic":
return anthropicCorpusBody(provider.Model, messages)View on GitHub (pinned to 27d5a3981a)
Solutions
- Clamp stableCount to min(stableCount, len(messages)) before calling if a shorter prefix is acceptable
- Validate the configured prefix depth against the shortest session and lower it or exclude tiny sessions
- Fix off-by-one in the caller computing the boundary
Example fix
// before
id, err := corpusStableIdentity(msgs, cfg.StablePrefix) // cfg=10, len(msgs)=3
// after
n := cfg.StablePrefix
if n > len(msgs) { n = len(msgs) }
id, err := corpusStableIdentity(msgs, n) Defensive patterns
Strategy: validation
Validate before calling
n := stableCount
if n > len(msgs) {
n = len(msgs) // or reject explicitly if a fixed depth is required
}
if n > len(msgs) {
return fmt.Errorf("stable prefix %d exceeds session length %d", stableCount, len(msgs))
}
id, err := corpusStableIdentity(msgs, n) Type guard
func validStableBoundary(msgs []CorpusMessage, n int) bool { return len(msgs) > 0 && n <= len(msgs) } Try / catch
if _, err := corpusStableIdentity(msgs, cfg.Prefix); err != nil {
if cfg.Prefix > len(msgs) {
cfg.Prefix = len(msgs) // degrade gracefully for short sessions
}
} Prevention
- Clamp configured prefix depth to the shortest session before running identity derivation
- Use min() semantics on the boundary instead of trusting config
- Add a test with sessions shorter than the configured prefix
When it happens
Trigger: Calling corpusStableIdentity(messages, N) with N > len(messages) — e.g. a fixed prefix window (say 10) applied to a short 3-message session, or an off-by-one where stableCount was set to len(messages)+1.
Common situations: Configured stable-prefix depth larger than the shortest session in the corpus; loop bounds using <= instead of <; prefix depth carried over from a different corpus with longer sessions.
Related errors
- cachebench: nil corpus reader
- message exceeds byte limit
- tool message requires tool_call_id
- cachebench: invalid corpus
- cachebench: no providers
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/b06a1ddc2462cfe5.
Report an issue: GitHub.