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

  1. Remove null entries from TimestampFilters before calling the filter's Apply / FindWorkflowInstances pipeline.
  2. On the client side, only send populated filter objects (skip empty filter rows before serializing).
  3. Deserialize into a collection that filters out nulls, or use non-nullable element types so nulls fail earlier.
  4. 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

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


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)