Skip to content

Improve the timeout error when closing an incompletely consumed SqlDataReader #4639

Description

@mdaigle

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

  1. Execute a query that returns enough rows that draining them exceeds a short CommandTimeout.
  2. Read only the first row.
  3. Call SqlDataReader.Close() or CloseAsync() without first canceling the command.
  4. 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.

Activity

  1. added theissue type on Sep 3, 2026
  2. priyankatiwari08 commented on Sep 17, 2026

    @priyankatiwari08
    Contributor

    /triage

  3. github-actions commented on Sep 17, 2026

    @github-actions

    🔍 Triage Summary (on-demand re-triage)

    Check Result
    Issue type Bug
    Environment All required environment details provided for investigation
    Area Area\Managed SNI
    Duplicates Potentially related: #4638, #1530 (parent issue)
    Regression Not indicated — reproduced consistently across Microsoft.Data.SqlClient 5.1.5 through 7.1.0-preview2

    Analysis

    This issue asks for an improved, more actionable error message when SqlDataReader.Close()/CloseAsync() times out while draining an incompletely consumed result set on Linux (Managed SNI path), rather than surfacing an opaque Win32Exception (258): Unknown error 258. It is a documentation/diagnostics improvement on top of already-understood behavior (Cause B from #1530), not a new functional defect, so it is best classified as a P2 usability/diagnostics enhancement. The fix would likely live in SqlDataReader.Close/CloseAsync and the TDS parser's row-draining path, where the timeout exception is caught/wrapped before being rethrown.

    Next Steps

    • Recommend reviewing Preserve the original exception when SqlDataReader teardown also times out #4638 ("Preserve the original exception when SqlDataReader teardown also times out") and parent Intermittent Unknown error 258 with no obvious cause #1530 together with this issue, since all three describe related aspects of the same close/drain timeout behavior — a combined fix may be more efficient than three separate PRs.
    • Assign this issue to the Copilot coding agent to investigate SqlDataReader.Close/CloseAsync in src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ and wrap the timeout SqlException/Win32Exception raised during drain with additional context (e.g. a message noting the timeout occurred while closing an incompletely consumed reader, with guidance to consume the result set or cancel the command first), while preserving the original exception as inner exception per Preserve the original exception when SqlDataReader teardown also times out #4638's ask.
    • Ensure any fix adds unit/manual tests covering both Close() and CloseAsync() paths on the Managed SNI code path, per repository testing guidelines (cover sync and async variants).

    Note: This triage summary is auto-generated by an AI agent. The analysis and suggestions above have not been verified by a human maintainer. Please treat as preliminary guidance only.

    Generated by SqlClient Issue Auto-Triage for #4639 · copilot · auto · 66.8 AIC · ⌖ 13.1 AIC · ⊞ 11.9K · ◷

  4. moved this from To triage to Backlog in SqlClient Boardon Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area\Managed SNIIssues that are targeted to the Managed SNI codebase.

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions