{"record":{"id":"8c17f8b909d70cd1","repo":"crowdsecurity/crowdsec","slug":"element-at-index-d-is-not-a-time-time","errorCode":null,"errorMessage":"element at index %d is not a time.Time","messagePattern":"element at index (.+?) is not a time\\.Time","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/exprhelpers/helpers.go","lineNumber":677,"sourceCode":"\n// func AverageInterval(times []time.Time) time.Duration\nfunc AverageInterval(params ...any) (any, error) {\n\tif len(params) != 1 {\n\t\treturn 0, errors.New(\"AverageInterval expects exactly one parameter: a slice of times\")\n\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++ {","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/exprhelpers/helpers.go#L659-L695","documentation":"AverageInterval computes the mean duration between consecutive timestamps in a slice. When the expression runtime passes a []interface{}, each element is asserted to time.Time; if any element is a different type (string, float, nil), the function stops and returns this error with the offending index, because it cannot do time arithmetic on non-time values.","triggerScenarios":"Calling AverageInterval() in an expr expression on an event field that is a []interface{} containing non-time.Time elements, e.g. event.GetField('leaks') built from parsed logs where entries were stored as strings or numbers instead of time.Time.","commonSituations":"Parser nodes storing raw string dates into a list field instead of parsed timestamps; expression built before a date parser node (ParseDate) was applied; nil entries in the slice from missing optional fields.","solutions":["Parse each element to time.Time before averaging: ensure the field is populated via a ParseDate node so elements are time.Time","Check the element at the reported index in your data — it will show the unexpected type","If elements are strings, convert them first (e.g. a helper that parses each entry) rather than passing raw strings","Guard the expression so AverageInterval is only evaluated when the field was produced by a date parser"],"exampleFix":"// before\nAverageInterval(event.GetField('leaks')) // elements are strings\n// after\n// ensure a parse node precedes it, e.g. list populated via ParseDate so elements are time.Time","handlingStrategy":"type-guard","validationCode":"// expr: all elements must be times\n// len(times) > 0 && ...","typeGuard":"func allTimes(v []interface{}) bool {\n\tfor _, item := range v {\n\t\tif _, ok := item.(time.Time); !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn len(v) > 0\n}","tryCatchPattern":null,"preventionTips":["Populate slice fields via ParseDate so elements are time.Time","Never store raw string timestamps in fields later used by time helpers","Test expressions against events with missing/nil entries"],"tags":["expr","type-mismatch","time"],"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"}