JuliusBrussee/caveman · error
cacheengine: invalid cache thresholds
Error message
cacheengine: invalid cache thresholds
What it means
Thrown by validatePlanRequest for any profile mode other than ModeUnsupported when threshold fields are out of range: MaxBreakpoints must be > 0, and MinPrefixTokens, MaxRPMPerKey, and TTL must all be >= 0. These thresholds drive breakpoint selection and key rotation, so zero/negative values would break planning.
Source
Thrown at cacheengine/engine.go:290
if !validIdentity(request.Epoch, 4096, false) {
return errors.New("cacheengine: invalid epoch")
}
if !validIdentity(request.PartitionKey, 4096, true) {
return errors.New("cacheengine: invalid partition key")
}
if request.ExpectedCalls < 0 || request.ExpectedRequestsPerMinute < 0 {
return errors.New("cacheengine: negative traffic expectation")
}
profile := normalizedProfile(request.Profile)
if !validIdentity(profile.ID, 256, false) || !validIdentity(profile.Provider, 64, true) || !validIdentity(profile.OptimizerID, 256, true) {
return errors.New("cacheengine: invalid profile identity")
}
if profile.Mode != ModeUnsupported && profile.Mode != ModeImplicit && profile.Mode != ModeAffinity && profile.Mode != ModeExplicit {
return fmt.Errorf("cacheengine: unknown mode %q", profile.Mode)
}
if profile.Mode != ModeUnsupported {
if profile.MaxBreakpoints <= 0 || profile.MinPrefixTokens < 0 || profile.MaxRPMPerKey < 0 || profile.TTL < 0 {
return errors.New("cacheengine: invalid cache thresholds")
}
switch profile.Attribution {
case AttributionNone, AttributionOrganic, AttributionAffinity, AttributionCausal:
default:
return fmt.Errorf("cacheengine: unknown attribution %q", profile.Attribution)
}
if profile.EconomicsKnown && (!finiteNonNegative(profile.WriteMultiplier) || !finiteNonNegative(profile.ReadMultiplier)) {
return errors.New("cacheengine: invalid cache economics")
}
}
return nil
}
func normalizedProfile(profile Profile) Profile {
if profile.Mode == ModeUnsupported {
if profile.ID == "" {
profile.ID = "unsupported"
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Set MaxBreakpoints to a positive value (e.g. 4) whenever the mode is not ModeUnsupported
- Use 0 rather than negative values for MinPrefixTokens/MaxRPMPerKey/TTL when you want the 'none' behavior
- Validate loaded config numbers before building the PlanRequest
Example fix
// before
profile := cacheengine.Profile{ID: "p", Mode: cacheengine.ModeImplicit} // MaxBreakpoints zero value = 0
// after
profile := cacheengine.Profile{ID: "p", Mode: cacheengine.ModeImplicit, MaxBreakpoints: 4, MinPrefixTokens: 1024, TTL: 5 * time.Minute} Defensive patterns
Strategy: validation
Validate before calling
func thresholdsOK(p cacheengine.Profile) bool {
if p.Mode == cacheengine.ModeUnsupported { return true }
return p.MaxBreakpoints > 0 && p.MinPrefixTokens >= 0 && p.MaxRPMPerKey >= 0 && p.TTL >= 0
} Type guard
// n/a
Prevention
- Unit-test profile construction so MaxBreakpoints is never the zero value
- Validate config-loaded numbers before building the request
When it happens
Trigger: Calling Plan with ModeImplicit/ModeAffinity/ModeExplicit and MaxBreakpoints == 0 (often the zero value of an unset struct field), a negative TTL, negative MinPrefixTokens, or negative MaxRPMPerKey.
Common situations: Constructing a Profile literal and forgetting MaxBreakpoints (int zero value is 0, which fails the > 0 check); loading thresholds from YAML/JSON where a typo yields 0; passing a negative TTL to mean 'no expiry'.
Related errors
- cacheengine: invalid partition key
- cacheengine: negative traffic expectation
- cacheengine: invalid profile identity
- cacheengine: invalid cache economics
- cacheengine: stable segment needs name and content
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/176a27be5619ec5d.
Report an issue: GitHub.