FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Components-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a linear regex · Issue #3101 · microsoft/OpenAPI.NET · GitHub

Repository navigation

Components-key validation can fail LoadAsync under load: 100 ms wall-clock timeout on a linear regex #3101

Description

Describe the bug

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:

internal static readonly Regex KeyRegex = new(@"^[a-zA-Z0-9\.\-_]+$", RegexOptions.None, TimeSpan.FromMilliseconds(100));

(source at v3.9.0; unchanged at v3.10.2)

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).

Activity

  1. 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
  2. Blind-Striker commented on Oct 4, 2026

    Author

    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.

  3. baywet commented on Oct 7, 2026

    Member

    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?

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL