{"record":{"id":"4cd14fe9c4ec2236","repo":"elsa-workflows/elsa-core","slug":"timestamp-filter-must-be-specified","errorCode":null,"errorMessage":"Timestamp filter must be specified.","messagePattern":"Timestamp filter must be specified\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Management/Filters/WorkflowInstanceFilter.cs","lineNumber":170,"sourceCode":"        if (!string.IsNullOrWhiteSpace(filter.CorrelationId)) query = query.Where(x => x.CorrelationId == filter.CorrelationId);\n        if (filter.CorrelationIds != null) query = query.Where(x => filter.CorrelationIds.Contains(x.CorrelationId!));\n        if (filter.Names != null) query = query.Where(x => filter.Names.Contains(x.Name!));\n        if (filter.WorkflowStatus != null) query = query.Where(x => x.Status == filter.WorkflowStatus);\n        if (filter.WorkflowSubStatus != null) query = query.Where(x => x.SubStatus == filter.WorkflowSubStatus);\n        if (filter.WorkflowStatuses != null) query = query.Where(x => filter.WorkflowStatuses.Contains(x.Status));\n        if (filter.WorkflowSubStatuses != null) query = query.Where(x => filter.WorkflowSubStatuses.Contains(x.SubStatus));\n        if (filter.IsExecuting != null) query = query.Where(x => x.IsExecuting == filter.IsExecuting);\n        if (filter.HasIncidents != null) query = filter.HasIncidents == true ? query.Where(x => x.IncidentCount > 0) : query.Where(x => x.IncidentCount == 0);\n        if (filter.IsSystem != null) query = query.Where(x => x.IsSystem == filter.IsSystem);\n        if (filter.Name != null) query = query.Where(x => x.Name!.ToLower().Contains(filter.Name.ToLower()));\n        if (filter.BeforeLastUpdated != null) query = query.Where(x => x.UpdatedAt < filter.BeforeLastUpdated);\n\n        if (TimestampFilters != null)\n        {\n            foreach (var timestampFilter in TimestampFilters)\n            {\n                if (timestampFilter == null)\n                    throw new ArgumentException(\"Timestamp filter must be specified.\", nameof(TimestampFilters));\n\n                var column = NormalizeTimestampFilterColumn(timestampFilter.Column);\n                var timestamp = timestampFilter.Timestamp;\n                var isZeroTime = timestamp.TimeOfDay == TimeSpan.Zero;\n                var startDay = new DateTimeOffset(timestamp.Date);\n                var endDay = startDay.AddDays(1);\n\n                query = timestampFilter.Operator switch\n                {\n                    TimestampFilterOperator.Is when isZeroTime => query.Where($\"{column} >= @0 && {column} < @1\", startDay, endDay),\n                    TimestampFilterOperator.Is => query.Where($\"{column} == @0\", timestamp),\n                    TimestampFilterOperator.IsNot when isZeroTime => query.Where($\"{column} < @0 || {column} >= @1\", startDay, endDay),\n                    TimestampFilterOperator.IsNot => query.Where($\"{column} != @0\", timestamp),\n                    TimestampFilterOperator.GreaterThan when isZeroTime => query.Where($\"{column} > @0\", endDay),\n                    TimestampFilterOperator.GreaterThan => query.Where($\"{column} > @0\", timestamp),\n                    TimestampFilterOperator.GreaterThanOrEqual when isZeroTime => query.Where($\"{column} >= @0\", startDay),\n                    TimestampFilterOperator.GreaterThanOrEqual => query.Where($\"{column} >= @0\", timestamp),\n                    TimestampFilterOperator.LessThan when isZeroTime => query.Where($\"{column} < @0\", startDay),","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Management/Filters/WorkflowInstanceFilter.cs#L152-L188","documentation":"Thrown by WorkflowInstanceFilter.Apply when a TimestampFilters collection contains a null element. Each entry must be a fully populated timestamp filter (column + operator + timestamp) to build the date-range query, so a null entry is rejected as an invalid argument.","triggerScenarios":"Passing TimestampFilters = new[] { null } or a list containing nulls when calling the workflow instance filtering/finding APIs; deserialization producing null list entries when request payloads have placeholder rows; LINQ projection or mapping code creating empty slots in the collection.","commonSituations":"API clients sending arrays with empty/null filter objects, UI filter builders that add blank rows and serialize them as null, and generic list-building code that initializes capacity without filling entries.","solutions":["Remove null entries from TimestampFilters before calling the filter's Apply / FindWorkflowInstances pipeline.","On the client side, only send populated filter objects (skip empty filter rows before serializing).","Deserialize into a collection that filters out nulls, or use non-nullable element types so nulls fail earlier.","Validate/normalize the request model in your own endpoint before constructing WorkflowInstanceFilter."],"exampleFix":"// before\nfilter.TimestampFilters = new List<TimestampFilter> { null, new() { Column = \"Created\", ... } };\n\n// after\nfilter.TimestampFilters = new List<TimestampFilter>\n{\n    new() { Column = \"Created\", Operator = TimestampFilterOperator.IsBetween, Timestamp = date }\n};","handlingStrategy":"validation","validationCode":"if (filter.TimestampFilters?.Any(f => f is null) == true)\n    throw new ArgumentException(\"TimestampFilters contains null entries; remove them before applying the filter.\", nameof(filter));","typeGuard":"IReadOnlyList<TimestampFilter> Clean(IReadOnlyList<TimestampFilter>? src) =>\n    (src ?? Array.Empty<TimestampFilter>()).Where(f => f is not null).ToList();","tryCatchPattern":"try\n{\n    filter.Apply(query);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Timestamp filter must be specified\"))\n{\n    logger.LogWarning(ex, \"Request contained null timestamp filters; ignoring them\");\n    filter.TimestampFilters = filter.TimestampFilters!.Where(f => f != null).ToList();\n    filter.Apply(query);\n}","preventionTips":["Skip blank filter rows in the UI before serializing request payloads.","Use non-nullable element types or trim nulls immediately after deserialization.","Validate filter models in your endpoint before calling Elsa's find/filter APIs."],"tags":["filtering","argument-validation","null-reference"],"backgroundTag":"null-argument","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}