Stream CopyToAsync never returns
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Stream.CopyToAsync hanging indefinitely is almost always caused by a deadlock from blocking on async code (calling .Result or .Wait() on the task) or by the source stream never signaling end-of-data. The fix depends on the root cause: use await instead of .Result, set HttpCompletionOption.ResponseHeadersRead for HTTP streams, or ensure the source stream has a finite length. This issue is especially common in ASP.NET, WPF, and WinForms applications where the SynchronizationContext serializes continuations onto a single thread.
The Deadlock Pattern
The SynchronizationContext in ASP.NET (pre-Core), WPF, and WinForms captures the current thread for continuations. When you call .Result, you block that thread. The await continuation in CopyToAsync needs to resume on that same thread, but it is blocked — deadlock.
ConfigureAwait(false) Workaround
ConfigureAwait(false) tells the continuation not to marshal back to the original context, avoiding the deadlock. However, the proper fix is to use async/await throughout the call chain.
HTTP Response Stream Hanging
With the default HttpCompletionOption.ResponseContentRead, GetAsync buffers the entire response body before returning. For large responses, this can cause memory issues or apparent hangs. ResponseHeadersRead returns as soon as headers arrive, letting you stream the body incrementally.
Source Stream Never Ends
GZipStream / DeflateStream Issues
Proper Pattern with CancellationToken
Common Pitfalls
- Calling
.Resultor.Wait()on CopyToAsync in UI or ASP.NET contexts: This causes a classic deadlock. The calling thread holds the SynchronizationContext, and the async continuation needs that same context to resume. Useawaitthroughout the call chain, or as a last resort, useConfigureAwait(false)before.GetAwaiter().GetResult(). - Not setting
HttpCompletionOption.ResponseHeadersReadfor large downloads: The default behavior buffers the entire HTTP response into memory beforeCopyToAsyncstarts. For large files, this looks like a hang while the buffer fills. UseResponseHeadersReadto start streaming immediately. - CopyToAsync on a stream that never signals end-of-data: Network streams, named pipes, and console input streams may never return 0 bytes from
ReadAsync. Without aCancellationTokenor known content length,CopyToAsyncwaits forever. Always pass a cancellation token with a timeout for network streams. - Forgetting to reset MemoryStream.Position after writing: After
CopyToAsyncwrites to aMemoryStream, the position is at the end. Reading from it without resetting position to 0 returns nothing, making it appear empty. Callms.Position = 0or usems.ToArray()to get all bytes regardless of position. - Not disposing GZipStream/DeflateStream before reading output: Compression streams write final bytes (footer, checksum) during
Dispose/Close. If you read the destination stream before the compression stream is disposed, the output is incomplete. Use ausingblock to ensure the compression stream flushes completely.
Summary
- The most common cause of
CopyToAsynchanging is blocking with.Resultor.Wait()in a SynchronizationContext — useawaitinstead - For HTTP streams, use
HttpCompletionOption.ResponseHeadersReadto avoid buffering the entire response - Always pass a
CancellationTokenwith a timeout when copying from network streams - Reset
MemoryStream.Positionto 0 after writing before reading - Dispose compression streams before reading their output to ensure all bytes are flushed
Related reading
- Strict serializability example clarification?
- Swagger async controller generation
- Swift Async let with loop
- Swift closure async order of execution
- Stream.Seek0, SeekOrigin.Begin or Position 0
- String interning in .NET Framework - What are the benefits and when to use interning
- StreamCorruptedException invalid type code AC
- String Resource new line /n not possible?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.