Skip to content

Add missing ConfigureAwait(false) to prevent deadlocks#2367

Merged
alexeyzimarev merged 2 commits intodevfrom
fix/missing-configure-await-false
Mar 5, 2026
Merged

Add missing ConfigureAwait(false) to prevent deadlocks#2367
alexeyzimarev merged 2 commits intodevfrom
fix/missing-configure-await-false

Conversation

@alexeyzimarev
Copy link
Member

Summary

  • Adds missing .ConfigureAwait(false) to all await calls in the RestSharp source that were missing it, preventing sync-over-async deadlocks on .NET Framework and environments with a SynchronizationContext (WinForms, WPF, ASP.NET classic)
  • Fixes: HttpResponseExtensions.GetResponseString, RestResponse.FromHttpResponse, RestClientExtensions.ExecuteAsync<T>, and RestClientExtensions.StreamJsonAsync<T>

Fixes #2083

Context

Reported by @deAtog in #2083 (comment) — when sync methods like ExecuteGet are used (which internally call AsyncHelpers.RunSync), any nested await without .ConfigureAwait(false) can capture the synchronization context and deadlock.

Test plan

  • Solution builds with 0 errors
  • Verified no remaining await calls without .ConfigureAwait(false) in src/RestSharp/

🤖 Generated with Claude Code

Fixes #2083

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Contributor

Review Summary by Qodo

Add missing ConfigureAwait(false) to prevent deadlocks

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Adds missing .ConfigureAwait(false) to prevent sync-over-async deadlocks
• Fixes deadlock in ExecuteGet when used with ThreadPool
• Ensures proper context handling in .NET Framework and WinForms/WPF
• Covers four critical async methods across RestSharp codebase
Diagram
flowchart LR
  A["Sync Methods<br/>ExecuteGet"] -->|calls| B["AsyncHelpers.RunSync"]
  B -->|awaits| C["Async Operations<br/>without ConfigureAwait"]
  C -->|captures| D["SynchronizationContext"]
  D -->|causes| E["Deadlock"]
  F["Fix: Add<br/>ConfigureAwait(false)"] -->|prevents| D
Loading

Grey Divider

File Changes

1. src/RestSharp/Extensions/HttpResponseExtensions.cs 🐞 Bug fix +1/-1

Add ConfigureAwait to response string reading

• Added .ConfigureAwait(false) to reader.ReadToEndAsync() call
• Prevents context capture in GetResponseString method

src/RestSharp/Extensions/HttpResponseExtensions.cs


2. src/RestSharp/Response/RestResponse.cs 🐞 Bug fix +1/-1

Add ConfigureAwait to response content retrieval

• Added .ConfigureAwait(false) to GetResponseString await call
• Ensures proper async context handling in response deserialization

src/RestSharp/Response/RestResponse.cs


3. src/RestSharp/RestClient.Extensions.cs 🐞 Bug fix +3/-3

Add ConfigureAwait to deserialization and streaming methods

• Added .ConfigureAwait(false) to Deserialize<T> await call in ExecuteAsync<T>
• Added .ConfigureAwait(false) to both ReadLineAsync calls in StreamJsonAsync<T> method
• Covers both .NET 7+ and earlier framework versions

src/RestSharp/RestClient.Extensions.cs


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 5, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. RestResponse.cs header mismatch 📘 Rule violation ✓ Correctness
Description
src/RestSharp/Response/RestResponse.cs does not contain the exact required Apache-2.0 license
header text even though the file is modified in this PR. This fails the repository licensing
compliance requirement for changed /src C# files.
Code

src/RestSharp/Response/RestResponse.cs[57]

+            var content = bytes == null ? null : await httpResponse.GetResponseString(bytes, options.Encoding).ConfigureAwait(false);
Evidence
Compliance requires every modified /src C# file to include the exact Apache-2.0 header defined in
.github/copilot-instructions.md. The header at the top of RestResponse.cs differs in
spacing/formatting from the required header text.

CLAUDE.md
.github/copilot-instructions.md[67-81]
src/RestSharp/Response/RestResponse.cs[1-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`src/RestSharp/Response/RestResponse.cs` does not match the repository’s exact required Apache-2.0 license header text.

## Issue Context
Compliance requires every modified `/src` C# file to include the exact header as defined in `.github/copilot-instructions.md`.

## Fix Focus Areas
- src/RestSharp/Response/RestResponse.cs[1-14]
- .github/copilot-instructions.md[65-81]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Deadlock fix lacks tests 📘 Rule violation ⛯ Reliability
Description
This PR changes async flow to prevent sync-over-async deadlocks, but it does not add/update tests to
cover the reported hang scenario. Without a regression test, the deadlock could reappear unnoticed.
Code

src/RestSharp/RestClient.Extensions.cs[R45-49]

            Ensure.NotNull(request, nameof(request));

            var response = await client.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
-            return await client.Serializers.Deserialize<T>(request, response, client.Options, cancellationToken);
+            return await client.Serializers.Deserialize<T>(request, response, client.Options, cancellationToken).ConfigureAwait(false);
        }
Evidence
The checklist requires adding coverage when fixing bugs/regressions. The PR description indicates a
deadlock fix (#2083), but the stated test plan only mentions build and a code search, not
adding/updating tests.

CLAUDE.md
src/RestSharp/RestClient.Extensions.cs[41-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR fixes a deadlock risk (sync-over-async) by adding `.ConfigureAwait(false)`, but there is no regression test to ensure the original hang scenario stays fixed.

## Issue Context
The reported issue involves sync methods (like `ExecuteGet`/`AsyncHelpers.RunSync`) hanging when invoked from ThreadPool work items due to `SynchronizationContext` capture.

## Fix Focus Areas
- src/RestSharp/RestClient.Extensions.cs[41-49]
- test/RestSharp.Tests/Fixtures/MockHttpClient.cs[1-17]
- test/RestSharp.Tests/[new test file covering ThreadPool ExecuteGet scenario]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 5, 2026

Deploying restsharp with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4d84167
Status:⚡️  Build in progress...

View logs


var bytes = stream == null ? null : await stream.ReadAsBytes(cancellationToken).ConfigureAwait(false);
var content = bytes == null ? null : await httpResponse.GetResponseString(bytes, options.Encoding);
var content = bytes == null ? null : await httpResponse.GetResponseString(bytes, options.Encoding).ConfigureAwait(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Restresponse.cs header mismatch 📘 Rule violation ✓ Correctness

src/RestSharp/Response/RestResponse.cs does not contain the exact required Apache-2.0 license
header text even though the file is modified in this PR. This fails the repository licensing
compliance requirement for changed /src C# files.
Agent Prompt
## Issue description
`src/RestSharp/Response/RestResponse.cs` does not match the repository’s exact required Apache-2.0 license header text.

## Issue Context
Compliance requires every modified `/src` C# file to include the exact header as defined in `.github/copilot-instructions.md`.

## Fix Focus Areas
- src/RestSharp/Response/RestResponse.cs[1-14]
- .github/copilot-instructions.md[65-81]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 45 to 49
Ensure.NotNull(request, nameof(request));

var response = await client.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
return await client.Serializers.Deserialize<T>(request, response, client.Options, cancellationToken);
return await client.Serializers.Deserialize<T>(request, response, client.Options, cancellationToken).ConfigureAwait(false);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Deadlock fix lacks tests 📘 Rule violation ⛯ Reliability

This PR changes async flow to prevent sync-over-async deadlocks, but it does not add/update tests to
cover the reported hang scenario. Without a regression test, the deadlock could reappear unnoticed.
Agent Prompt
## Issue description
The PR fixes a deadlock risk (sync-over-async) by adding `.ConfigureAwait(false)`, but there is no regression test to ensure the original hang scenario stays fixed.

## Issue Context
The reported issue involves sync methods (like `ExecuteGet`/`AsyncHelpers.RunSync`) hanging when invoked from ThreadPool work items due to `SynchronizationContext` capture.

## Fix Focus Areas
- src/RestSharp/RestClient.Extensions.cs[41-49]
- test/RestSharp.Tests/Fixtures/MockHttpClient.cs[1-17]
- test/RestSharp.Tests/[new test file covering ThreadPool ExecuteGet scenario]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

Test Results

   42 files     42 suites   17m 37s ⏱️
  562 tests   562 ✅ 0 💤 0 ❌
3 922 runs  3 922 ✅ 0 💤 0 ❌

Results for commit b4dc236.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@alexeyzimarev alexeyzimarev merged commit c362621 into dev Mar 5, 2026
9 of 10 checks passed
@alexeyzimarev alexeyzimarev deleted the fix/missing-configure-await-false branch March 5, 2026 11:54
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 5, 2026

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ThreadPool hang

1 participant