{"record":{"id":"3f8b7b792afab840","repo":"crowdsecurity/crowdsec","slug":"need-at-least-two-times-to-calculate-an-average-in","errorCode":null,"errorMessage":"need at least two times to calculate an average interval","messagePattern":"need at least two times to calculate an average interval","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/exprhelpers/helpers.go","lineNumber":686,"sourceCode":"\t// Handle both []time.Time and []interface{} (from expr map function)\n\tswitch v := params[0].(type) {\n\tcase []time.Time:\n\t\ttimes = v\n\tcase []interface{}:\n\t\ttimes = make([]time.Time, len(v))\n\t\tfor i, item := range v {\n\t\t\tt, ok := item.(time.Time)\n\t\t\tif !ok {\n\t\t\t\treturn 0, fmt.Errorf(\"element at index %d is not a time.Time\", i)\n\t\t\t}\n\t\t\ttimes[i] = t\n\t\t}\n\tdefault:\n\t\treturn 0, errors.New(\"AverageInterval expects a slice of times\")\n\t}\n\n\tif len(times) < 2 {\n\t\treturn 0, errors.New(\"need at least two times to calculate an average interval\")\n\t}\n\n\t// Sort times in ascending order\n\tsort.Slice(times, func(i, j int) bool {\n\t\treturn times[i].Before(times[j])\n\t})\n\n\tvar total time.Duration\n\tfor i := 1; i < len(times); i++ {\n\t\ttotal += times[i].Sub(times[i-1])\n\t}\n\n\taverage := time.Duration(int64(total) / int64(len(times)-1))\n\treturn average, nil\n}\n\n// func MedianInterval(times []time.Time) (time.Duration, error)\nfunc MedianInterval(params ...any) (any, error) {","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/exprhelpers/helpers.go#L668-L704","documentation":"After coercing the argument to a slice of times, AverageInterval needs at least two timestamps to compute an interval. With fewer than two it returns this error since an average gap is undefined for 0 or 1 points.","triggerScenarios":"Expression passes a slice with 0 or 1 time.Time elements, e.g. a single-event scenario bucket or empty map() result.","commonSituations":"Scenario triggers on the first matching event before a bucket has accumulated two events; filter removed all but one timestamp; empty meta list.","solutions":["Ensure the expression only runs when at least 2 events are in the bucket (condition on len(bucket) >= 2)","Guard the input: only call AverageInterval when the slice length is >= 2","Use an if/condition in the scenario so single-event evaluations don't invoke the helper"],"exampleFix":"// guard before calling\nlen(times) >= 2 ? AverageInterval(times) : 0","handlingStrategy":"validation","validationCode":"// expr guard\nlen(times) >= 2 && AverageInterval(times)","typeGuard":"func hasAtLeastTwoTimes(times []time.Time) bool { return len(times) >= 2 }","tryCatchPattern":null,"preventionTips":["Add a bucket condition requiring >= 2 events before computing averages","Handle first-event buckets (skip evaluation)","Check upstream filter didn't drop events leaving a 1-element slice"],"tags":["expr","scenario","crowdsec"],"backgroundTag":"insufficient-data-for-average","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}