{"record":{"id":"383994fe78ac0bee","repo":"crowdsecurity/crowdsec","slug":"averageinterval-expects-a-slice-of-times","errorCode":null,"errorMessage":"AverageInterval expects a slice of times","messagePattern":"AverageInterval expects a slice of times","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/exprhelpers/helpers.go","lineNumber":682,"sourceCode":"\t}\n\n\tvar times []time.Time\n\n\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","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/exprhelpers/helpers.go#L664-L700","documentation":"AverageInterval accepts the single parameter only if it is a []time.Time or an []interface{} whose elements are all time.Time. This error is thrown in the type-switch default branch when the argument is some other type (string, int, a single time.Time, etc.).","triggerScenarios":"Calling AverageInterval with a non-slice argument, e.g. a single time.Time, a string field, or a slice of non-time values (from expr's map without a time-producing expression).","commonSituations":"Scenario expression passes evt.Meta.timestamp (single time) instead of a slice; map() built strings instead of times; wrong meta field type.","solutions":["Ensure the argument is a slice of times: []time.Time or expr map(...) over time values","Wrap a single timestamp in a slice only if you have >=2, else the next check will also fail","Cast/convert fields to time.Time before calling, e.g. with parse_date helper"],"exampleFix":"// before\nAverageInterval(evt.Meta.timestamp)\n// after\nAverageInterval([evt.Meta.timestamp, evt.Alert.GetEvents()...]) or use map() over time values","handlingStrategy":"type-guard","validationCode":"// expr: only call with slices of times\ntypeOf(times) == \"[]time.Time\" && len(times) >= 2","typeGuard":"func isTimeSlice(v any) bool {\n    switch t := v.(type) {\n    case []time.Time:\n        return true\n    case []any:\n        for _, e := range t {\n            if _, ok := e.(time.Time); !ok {\n                return false\n            }\n        }\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Ensure map() expressions produce time.Time values (use parse_date if needed)","Don't pass single timestamps; wrap or accumulate into slices","Unit-test scenario expressions with cscli test fixtures"],"tags":["expr","type-mismatch","scenario","crowdsec"],"backgroundTag":"type-mismatch","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}