elsa-workflows/elsa-core · error · ArgumentException
Timestamp filter must be specified.
Error message
Timestamp filter must be specified.
What it means
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.
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.
Example fix
// before
filter.TimestampFilters = new List<TimestampFilter> { null, new() { Column = "Created", ... } };
// after
filter.TimestampFilters = new List<TimestampFilter>
{
new() { Column = "Created", Operator = TimestampFilterOperator.IsBetween, Timestamp = date }
}; Defensive patterns
Strategy: validation
Validate before calling
if (filter.TimestampFilters?.Any(f => f is null) == true)
throw new ArgumentException("TimestampFilters contains null entries; remove them before applying the filter.", nameof(filter)); Type guard
IReadOnlyList<TimestampFilter> Clean(IReadOnlyList<TimestampFilter>? src) =>
(src ?? Array.Empty<TimestampFilter>()).Where(f => f is not null).ToList(); Try / catch
try
{
filter.Apply(query);
}
catch (ArgumentException ex) when (ex.Message.Contains("Timestamp filter must be specified"))
{
logger.LogWarning(ex, "Request contained null timestamp filters; ignoring them");
filter.TimestampFilters = filter.TimestampFilters!.Where(f => f != null).ToList();
filter.Apply(query);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- A metadata key is required.
- A metadata value is required.
- Capacity must be greater than zero.
- Filtering workflow definitions by labels is not supported…
- The configured secret binding is invalid.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/4cd14fe9c4ec2236.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Management/Filters/WorkflowInstanceFilter.cs:170
if (!string.IsNullOrWhiteSpace(filter.CorrelationId)) query = query.Where(x => x.CorrelationId == filter.CorrelationId);
if (filter.CorrelationIds != null) query = query.Where(x => filter.CorrelationIds.Contains(x.CorrelationId!));
if (filter.Names != null) query = query.Where(x => filter.Names.Contains(x.Name!));
if (filter.WorkflowStatus != null) query = query.Where(x => x.Status == filter.WorkflowStatus);
if (filter.WorkflowSubStatus != null) query = query.Where(x => x.SubStatus == filter.WorkflowSubStatus);
if (filter.WorkflowStatuses != null) query = query.Where(x => filter.WorkflowStatuses.Contains(x.Status));
if (filter.WorkflowSubStatuses != null) query = query.Where(x => filter.WorkflowSubStatuses.Contains(x.SubStatus));
if (filter.IsExecuting != null) query = query.Where(x => x.IsExecuting == filter.IsExecuting);
if (filter.HasIncidents != null) query = filter.HasIncidents == true ? query.Where(x => x.IncidentCount > 0) : query.Where(x => x.IncidentCount == 0);
if (filter.IsSystem != null) query = query.Where(x => x.IsSystem == filter.IsSystem);
if (filter.Name != null) query = query.Where(x => x.Name!.ToLower().Contains(filter.Name.ToLower()));
if (filter.BeforeLastUpdated != null) query = query.Where(x => x.UpdatedAt < filter.BeforeLastUpdated);
if (TimestampFilters != null)
{
foreach (var timestampFilter in TimestampFilters)
{
if (timestampFilter == null)
throw new ArgumentException("Timestamp filter must be specified.", nameof(TimestampFilters));
var column = NormalizeTimestampFilterColumn(timestampFilter.Column);
var timestamp = timestampFilter.Timestamp;
var isZeroTime = timestamp.TimeOfDay == TimeSpan.Zero;
var startDay = new DateTimeOffset(timestamp.Date);
var endDay = startDay.AddDays(1);
query = timestampFilter.Operator switch
{
TimestampFilterOperator.Is when isZeroTime => query.Where($"{column} >= @0 && {column} < @1", startDay, endDay),
TimestampFilterOperator.Is => query.Where($"{column} == @0", timestamp),
TimestampFilterOperator.IsNot when isZeroTime => query.Where($"{column} < @0 || {column} >= @1", startDay, endDay),
TimestampFilterOperator.IsNot => query.Where($"{column} != @0", timestamp),
TimestampFilterOperator.GreaterThan when isZeroTime => query.Where($"{column} > @0", endDay),
TimestampFilterOperator.GreaterThan => query.Where($"{column} > @0", timestamp),
TimestampFilterOperator.GreaterThanOrEqual when isZeroTime => query.Where($"{column} >= @0", startDay),
TimestampFilterOperator.GreaterThanOrEqual => query.Where($"{column} >= @0", timestamp),
TimestampFilterOperator.LessThan when isZeroTime => query.Where($"{column} < @0", startDay),View on GitHub (pinned to fe9217bdfa)