You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Components-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a linear regex #3101
OpenApiDocument.LoadAsync can fail on a valid document with RegexMatchTimeoutException when the machine is under load, even though the regex involved does only linear work.
Loading runs the default rule set. One rule in it, OpenApiComponentsRules.KeyMustBeRegularExpression, matches every components key against:
This is an interpreted Regex. The interpreter's scan calls CheckTimeout() before every match attempt and inside its loops. .NET regex timeouts are measured on the wall clock from the start of the match, so the check can fire for reasons unrelated to the regex. If the matching thread is descheduled, or paused by a garbage collection, for more than 100 ms while it matches a key, the match throws, even though matching that key takes microseconds. The exception escapes LoadAsync, so the document fails to load.
The pattern is a single anchored character-class loop. Its work is linear in the key length, and it cannot backtrack catastrophically. The timeout therefore protects nothing here and only makes loading nondeterministic.
(OpenApiResponsesRules.StatusCodeRegex also declares a 100 ms timeout. On net8.0 and later it is source-generated with no loop, and the generated code never checks the timeout, so it is not the cause. Downlevel targets build it as an interpreted Regex, where the same exposure applies.)
OpenApi File To Reproduce
Any valid document. The failure depends on machine load, not on the document's content.
We hit it in CI. Our test suite parses a 140-operation OpenAPI 3.1 document, with 380 components keys, more than a dozen times per run. On a busy Windows GitHub-hosted runner, that parse failed twice in about 200 runs with:
RegexMatchTimeoutException: The Regex engine has timed out while trying to match a pattern to an input string. ...
It never failed on Linux or macOS runners, or locally.
Expected behavior
Whether a key is valid should not depend on how busy the machine is. Any of these would remove the wall-clock dependency:
Regex.InfiniteMatchTimeout for these fixed, library-owned patterns, since they are not user input;
RegexOptions.NonBacktracking;
a source-generated regex ([GeneratedRegex]), as StatusCodeRegex already uses on net8.0 and later.
Screenshots/Code Snippets
To keep the default validation unchanged, we replaced this one rule in our reader's ValidationRuleSet with an equivalent that has no timeout. It accepts and refuses exactly the same keys and reports the same error. We will remove it once the library drops the timeout.
Additional context
Microsoft.OpenApi 3.9.0 (checked unchanged in 3.10.2), .NET 10, Windows Server GitHub-hosted runner. We found this while building a .NET SDK that generates from an OpenAPI 3.1 document (opencode-dotnet/opencode-sdk-dotnet).
changed the title [-]Response-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a non-backtracking regex[/-][+]Components-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a linear regex[/+]on Oct 4, 2026
Correction to the original report: I first attributed the timeout to OpenApiResponsesRules.StatusCodeRegex. On net8.0+ that regex is source-generated without a loop and its generated code never checks the timeout, so it cannot throw there. The timeout that can fire is OpenApiComponentsRules.KeyRegex (interpreted, checked by the interpreter on every match attempt). I have updated the title and description accordingly.
Is this something you'd like to submit a pull request for provided some guidance?
Regex.InfiniteMatchTimeout for these fixed, library-owned patterns, since they are not user inpu
We can't do that, the keys come from the document, which is user provided
RegexOptions.NonBacktracking;
Sure, that'll probably help, and we don't need backtracking for this one
a source-generated regex ([GeneratedRegex]), as StatusCodeRegex already uses on net8.0 and later.
Yes, let's do that as well, this is probably the best improvement here. Optionally if you find other instances that can use generated Regex, and you're willing to update them as well, it'd be appreciated.
Activity
[-]Response-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a non-backtracking regex[/-][+]Components-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a linear regex[/+]Blind-Striker commentedon Oct 4, 2026
Correction to the original report: I first attributed the timeout to
OpenApiResponsesRules.StatusCodeRegex. On net8.0+ that regex is source-generated without a loop and its generated code never checks the timeout, so it cannot throw there. The timeout that can fire isOpenApiComponentsRules.KeyRegex(interpreted, checked by the interpreter on every match attempt). I have updated the title and description accordingly.fix(tools): replace the reader's components-key rule with one that ha…
baywet commentedon Oct 7, 2026
Hi Deniz İrgin (@Blind-Striker)
Thank you for using the SDK and for reaching out.
Is this something you'd like to submit a pull request for provided some guidance?
We can't do that, the keys come from the document, which is user provided
Sure, that'll probably help, and we don't need backtracking for this one
Yes, let's do that as well, this is probably the best improvement here. Optionally if you find other instances that can use generated Regex, and you're willing to update them as well, it'd be appreciated.