{"record":{"id":"137257e92a7d9553","repo":"elsa-workflows/elsa-core","slug":"the-opentelemetry-filter-from-timestamp-must-be-earlier-than","errorCode":null,"errorMessage":"The OpenTelemetry filter 'from' timestamp must be earlier than or equal to 'to'.","messagePattern":"The OpenTelemetry filter 'from' timestamp must be earlier than or equal to 'to'\\.","errorType":"validation","errorClass":"HubException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetryHub.cs","lineNumber":38,"sourceCode":"    }\n\n    public Task UnsubscribeAsync()\n    {\n        return subscriptionManager.UnsubscribeAsync(Context.ConnectionId);\n    }\n\n    public override async Task OnDisconnectedAsync(Exception? exception)\n    {\n        await UnsubscribeAsync().ConfigureAwait(false);\n        await base.OnDisconnectedAsync(exception).ConfigureAwait(false);\n    }\n\n    private static OpenTelemetryTraceFilter ValidateFilter(OpenTelemetryTraceFilter? filter)\n    {\n        filter ??= new();\n\n        if (filter.From is { } from && filter.To is { } to && from > to)\n            throw new HubException(\"The OpenTelemetry filter 'from' timestamp must be earlier than or equal to 'to'.\");\n\n        return filter;\n    }\n\n    private void EnsureCanReadOpenTelemetry()\n    {\n        var user = Context.User;\n\n        if (user?.Identity?.IsAuthenticated != true || !PermissionEvaluator.Shared.HasPermission(user, ReadOpenTelemetry))\n            throw new HubException(\"Access denied.\");\n    }\n}\n","sourceCodeStart":20,"sourceCodeEnd":51,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetryHub.cs#L20-L51","documentation":"ValidateFilter normalizes the OpenTelemetryTraceFilter passed to OpenTelemetryHub.SubscribeAsync and enforces chronological consistency: if both From and To timestamps are set and From is later than To, the filter can never match, so a HubException is thrown before subscribing.","triggerScenarios":"Calling SubscribeAsync with a filter where filter.From > filter.To, e.g. a Studio client passing swapped or user-entered date-range values over SignalR.","commonSituations":"UI sending 'last N minutes' ranges with from/to computed in the wrong order; timezone conversion flipping the range; string dates parsed into DateTimes in inconsistent kinds producing inverted comparisons.","solutions":["Swap the values client-side when from > to before subscribing.","Validate the date range in the UI/form before sending the subscribe request.","If only one bound is needed, send only From or To instead of an inverted pair."],"exampleFix":"// before\nawait hub.SubscribeAsync(new OpenTelemetryTraceFilter { From = to, To = from });\n\n// after\nvar filter = new OpenTelemetryTraceFilter { From = from, To = to };\nif (filter.From > filter.To)\n    (filter.From, filter.To) = (filter.To, filter.From);\nawait hub.SubscribeAsync(filter);","handlingStrategy":"validation","validationCode":"if (filter.From is { } f && filter.To is { } t && f > t)\n    (filter.From, filter.To) = (t, f); // normalize before subscribing","typeGuard":null,"tryCatchPattern":"try { await hub.SubscribeAsync(filter); }\ncatch (HubException ex) when (ex.Message.Contains(\"earlier than or equal to\"))\n{ logger.LogWarning(ex, \"Invalid live-trace filter range rejected by hub.\"); }","preventionTips":["Normalize from/to ranges in the UI layer so the earlier bound is always From.","Compare timestamps in a consistent UTC kind before sending the filter."],"tags":["signalr","validation","date-range","opentelemetry"],"backgroundTag":"invalid-query-parameter","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}