fix(filter): recover from datemath panic on malformed date filter values

The go-datemath lexer panics with "scanner internal error" when given
certain malformed inputs like "no" (it starts recognizing "now" but
hits EOF). Wrap datemath.Parse in a recover so the panic becomes a
regular error, allowing the fallback date parser to handle it gracefully.

Closes go-vikunja/vikunja#2307
This commit is contained in:
kolaente 2026-02-26 16:09:04 +01:00
parent b6205bb809
commit 3d5ad73d4f
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
2 changed files with 20 additions and 1 deletions

View File

@ -284,6 +284,18 @@ func getFilterComparatorFromOp(op fexpr.SignOp) (taskFilterComparator, error) {
}
}
// safeDatemathParse wraps datemath.Parse with a recover to catch panics from
// the datemath lexer when given malformed input (e.g. "no" triggers a
// "scanner internal error" panic in the generated lexer).
func safeDatemathParse(s string) (expr datemath.Expression, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("datemath parse error: %v", r)
}
}()
return datemath.Parse(s)
}
func getValueForField(field reflect.StructField, rawValue string, loc *time.Location) (value interface{}, err error) {
if loc == nil {
@ -305,7 +317,7 @@ func getValueForField(field reflect.StructField, rawValue string, loc *time.Loca
if field.Type == schemas.TimeType {
var t datemath.Expression
var tt time.Time
t, err = datemath.Parse(rawValue)
t, err = safeDatemathParse(rawValue)
if err == nil {
tt = t.Time(datemath.WithLocation(loc)).In(config.GetTimeZone())
tt = adjustDateForMysql(tt)

View File

@ -311,4 +311,11 @@ func TestParseFilter(t *testing.T) {
assert.Equal(t, taskFilterComparatorEquals, firstSet[1].comparator)
assert.Equal(t, int64(1), firstSet[1].value)
})
t.Run("invalid date value should not panic", func(t *testing.T) {
// "no" triggers a panic in the datemath lexer because it starts
// recognizing "now" but hits EOF after "no". The safeDatemathParse
// wrapper must recover from this panic and return an error instead.
_, err := getTaskFiltersFromFilterString("due_date = no", "UTC")
require.Error(t, err)
})
}