Describe the bug
Closing a SqlDataReader before consuming the full result set drains the remaining rows while the command timeout is still armed. If the drain exceeds the timeout on Linux, the caller receives an opaque timeout ending in Win32Exception (258): Unknown error 258.
The behavior is expected, but the error does not explain that the timeout occurred while draining an incompletely consumed result set or suggest canceling the command before closing the reader.
This is Cause B from #1530. See the deterministic analysis and version matrix and the request to track an improved error separately.
Exception message: Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Inner exception: System.ComponentModel.Win32Exception (258): Unknown error 258
Stack trace: The exception is raised from SqlDataReader.Close/CloseAsync while draining the remaining rows.
To reproduce
- Execute a query that returns enough rows that draining them exceeds a short
CommandTimeout.
- Read only the first row.
- Call
SqlDataReader.Close() or CloseAsync() without first canceling the command.
- Observe the timeout with
Unknown error 258.
The linked analysis includes results across Microsoft.Data.SqlClient 5.1.5 through 7.1.0-preview2.
Expected behavior
Surface an error that identifies the timeout as occurring while closing and draining an incompletely consumed reader, with guidance to consume the result set or cancel the command before closing it.
Further technical details
Microsoft.Data.SqlClient version: Reproduced from 5.1.5 through 7.1.0-preview2
.NET target: net8.0 and net9.0 assets, tested on .NET 8, .NET 9, and .NET 10
SQL Server version: Reproduced with SQL Server in Docker
Operating system: Linux
Additional context
Explicit Close() and CloseAsync() surface the exception. Dispose() currently swallows the SqlException from Close(). EF Core calls the throwing close paths, while Dapper cancels the command during teardown and avoids this result.
Describe the bug
Closing a
SqlDataReaderbefore consuming the full result set drains the remaining rows while the command timeout is still armed. If the drain exceeds the timeout on Linux, the caller receives an opaque timeout ending inWin32Exception (258): Unknown error 258.The behavior is expected, but the error does not explain that the timeout occurred while draining an incompletely consumed result set or suggest canceling the command before closing the reader.
This is Cause B from #1530. See the deterministic analysis and version matrix and the request to track an improved error separately.
To reproduce
CommandTimeout.SqlDataReader.Close()orCloseAsync()without first canceling the command.Unknown error 258.The linked analysis includes results across Microsoft.Data.SqlClient 5.1.5 through 7.1.0-preview2.
Expected behavior
Surface an error that identifies the timeout as occurring while closing and draining an incompletely consumed reader, with guidance to consume the result set or cancel the command before closing it.
Further technical details
Microsoft.Data.SqlClient version: Reproduced from 5.1.5 through 7.1.0-preview2
.NET target: net8.0 and net9.0 assets, tested on .NET 8, .NET 9, and .NET 10
SQL Server version: Reproduced with SQL Server in Docker
Operating system: Linux
Additional context
Explicit
Close()andCloseAsync()surface the exception.Dispose()currently swallows theSqlExceptionfromClose(). EF Core calls the throwing close paths, while Dapper cancels the command during teardown and avoids this result.