{"record":{"id":"a314c30487f5e694","repo":"elsa-workflows/elsa-core","slug":"status-code-count-must-be-greater-than-zero","errorCode":null,"errorMessage":"Status code count must be greater than zero.","messagePattern":"Status code count must be greater than zero\\.","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"warning","filePath":"src/modules/Elsa.Resilience/Endpoints/SimulateResponse/SimulateResponseSessionStore.cs","lineNumber":15,"sourceCode":"using Elsa.Resilience.Options;\nusing Microsoft.Extensions.Options;\n\nnamespace Elsa.Resilience.Endpoints.SimulateResponse;\n\npublic class SimulateResponseSessionStore(IOptions<SimulateResponseOptions> options, TimeProvider timeProvider)\n{\n    private readonly Dictionary<string, SessionState> _sessions = new(StringComparer.Ordinal);\n    private readonly object _lock = new();\n    private readonly SimulateResponseOptions _options = options.Value;\n\n    public bool TryGetNextIndex(string sessionId, int statusCodeCount, out int nextIndex)\n    {\n        if (statusCodeCount <= 0)\n            throw new ArgumentOutOfRangeException(nameof(statusCodeCount), \"Status code count must be greater than zero.\");\n\n        var now = timeProvider.GetUtcNow();\n        var expiresAt = now.Add(_options.SessionSlidingExpiration);\n\n        lock (_lock)\n        {\n            PruneExpired(now);\n\n            nextIndex = _sessions.TryGetValue(sessionId, out var state) ? Math.Min(state.NextIndex, statusCodeCount - 1) : 0;\n\n            if (nextIndex + 1 >= statusCodeCount)\n            {\n                _sessions.Remove(sessionId);\n                return true;\n            }\n\n            if (!_sessions.ContainsKey(sessionId) && _sessions.Count >= _options.SessionCapacity)\n                return false;","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Resilience/Endpoints/SimulateResponse/SimulateResponseSessionStore.cs#L1-L33","documentation":"The simulate-response session store rotates through a configured list of status codes per session. TryGetNextIndex computes which code comes next and requires statusCodeCount (the size of that list) to be at least 1; a zero or negative count is a programming error, so it throws ArgumentOutOfRangeException naming the parameter.","triggerScenarios":"Calling TryGetNextIndex with statusCodeCount <= 0 — typically when the caller built its status-code list from empty configuration, an empty array in options, or a filtering bug that removed all entries.","commonSituations":"Configuring SimulateResponse with an empty status-codes array and then invoking the simulation endpoint; deserializing configuration where the list was omitted; a code path that computes the count from a filtered/invalid session definition.","solutions":["Configure at least one status code for the simulation session before starting it.","Before calling, guard: if (codes == null || codes.Count == 0) handle/return an error instead of calling TryGetNextIndex.","Validate the simulation options at startup (or on session creation) so empty code lists are rejected with a clear message.","If the list is built dynamically, check the filter logic that may be dropping all entries."],"exampleFix":"// before\nstore.TryGetNextIndex(sessionId, codes.Count, out var idx); // codes is empty\n// after\nif (codes.Count == 0)\n    throw new InvalidOperationException(\"Simulate response session requires at least one status code.\");\nstore.TryGetNextIndex(sessionId, codes.Count, out var idx);","handlingStrategy":"validation","validationCode":"if (statusCodes is null || statusCodes.Count == 0)\n    throw new InvalidOperationException(\"A simulate-response session requires at least one status code.\");\nstore.TryGetNextIndex(sessionId, statusCodes.Count, out var next);","typeGuard":"static bool HasStatusCodes(System.Collections.Generic.IReadOnlyList<int> codes) => codes is { Count: > 0 };","tryCatchPattern":"try\n{\n    store.TryGetNextIndex(sessionId, count, out var next);\n}\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == nameof(count))\n{\n    logger.LogError(\"Simulate session '{SessionId}' has no status codes configured.\", sessionId);\n}","preventionTips":["Validate simulation options (non-empty status code list) at session creation.","Reject empty status-code arrays in config binding/startup validation.","Unit-test option parsing so missing lists fail early."],"tags":["argument","validation","resilience","simulation"],"backgroundTag":"argument-out-of-range","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"}