SigNoz/signoz · error
delete TTL should be greater than cold storage move TTL
Error message
delete TTL should be greater than cold storage move TTL
What it means
Data must live on hot storage longer than the cold-storage move threshold, so toColdDuration must be strictly less than the overall delete TTL duration. If toColdParsed >= durationParsed the request is rejected.
Source
Thrown at pkg/query-service/app/parser.go:455
return nil, fmt.Errorf("type param should be metrics|traces|logs, got %v", typeTTL)
}
// Validate the TTL duration.
durationParsed, err := time.ParseDuration(delDuration)
if err != nil || durationParsed.Seconds() <= 0 {
return nil, fmt.Errorf("not a valid TTL duration %v", delDuration)
}
var toColdParsed time.Duration
// If some cold storage is provided, validate the cold storage move TTL.
if len(coldStorage) > 0 {
toColdParsed, err = time.ParseDuration(toColdDuration)
if err != nil || toColdParsed.Seconds() <= 0 {
return nil, fmt.Errorf("not a valid toCold TTL duration %v", toColdDuration)
}
if toColdParsed.Seconds() != 0 && toColdParsed.Seconds() >= durationParsed.Seconds() {
return nil, fmt.Errorf("delete TTL should be greater than cold storage move TTL")
}
}
return &retentiontypes.TTLParams{
Type: typeTTL,
DelDuration: int64(durationParsed.Seconds()),
ColdStorageVolume: coldStorage,
ToColdStorageDuration: int64(toColdParsed.Seconds()),
}, nil
}
func parseGetTTL(r *http.Request) (*retentiontypes.GetTTLParams, error) {
typeTTL := r.URL.Query().Get("type")
if len(typeTTL) == 0 {
return nil, fmt.Errorf("type param cannot be empty from the query")
} else {View on GitHub (pinned to 5069bf80b0)
Solutions
- Make duration strictly greater than toColdDuration (e.g. duration=72h, toColdDuration=24h)
- If you intended no cold tier, remove the coldStorage and toColdDuration params entirely
- Re-read the semantics: duration = total retention before delete; toColdDuration = age at which data moves to cold
Example fix
// before ?type=traces&duration=24h&coldStorage=s3&toColdDuration=48h // after ?type=traces&duration=72h&coldStorage=s3&toColdDuration=24h
Defensive patterns
Strategy: validation
Validate before calling
del, _ := time.ParseDuration(duration)
move, _ := time.ParseDuration(toColdDuration)
if move >= del { return fmt.Errorf("toColdDuration must be < duration") } Prevention
- Derive toColdDuration from duration programmatically (e.g. duration/3) instead of hardcoding both
- Alert on config review when either value changes
When it happens
Trigger: ?duration=24h&toColdDuration=24h, or ?duration=24h&toColdDuration=48h — any case where the move-to-cold age meets or exceeds the deletion age.
Common situations: Misreading which param is which and swapping them; incrementing retention duration without adjusting toColdDuration; equal-value configs.
Related errors
- not a valid toCold TTL duration %v
- SetTTLV2 only supported
- error while getting ttl. Err=%v
- type and duration param cannot be empty from the query
- type param should be metrics|traces|logs, got %v
AI-assisted analysis of SigNoz/signoz@5069bf80b0 (2026-08-28).
Data as JSON: /api/errors/8ce9563cf891447d.
Report an issue: GitHub.