microsoft/garnet · error · ObjectDisposedException
GarnetClientSession
Error message
GarnetClientSession
What it means
ReconnectAsync in GarnetClientSession guards against reuse of a disposed session by checking the Disposed property and throwing ObjectDisposedException named 'GarnetClientSession'. Before reconnecting it attempts to clean up the prior networkSender/networkHandler/socket (swallowing errors) and then calls ConnectAsync. This guard means: once Disposed is true, the session is permanently dead and cannot be resurrected.
Source
Thrown at libs/client/ClientSession/GarnetClientSession.cs:399
await socket.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false);
}
}
catch (Exception ex)
{
logger?.LogWarning(ex, "Failed at GarnetClient.TryConnectSocketAsync");
socket.Dispose();
return false;
}
return true;
}
/// <summary>
/// Reconnect to server
/// </summary>
public Task ReconnectAsync(int timeoutMs = 0, CancellationToken token = default)
{
if (Disposed) throw new ObjectDisposedException("GarnetClientSession");
try
{
networkSender?.ReturnResponseObject();
socket?.Dispose();
networkHandler?.Dispose();
}
catch { }
return ConnectAsync(timeoutMs, token);
}
/// <summary>
/// Dispose instance
/// </summary>
public void Dispose()
{
if (Interlocked.Increment(ref disposed) > 1) return;
networkSender?.ReturnResponseObject();View on GitHub (pinned to 951b0fc683)
Solutions
- Track lifecycle explicitly: never call ReconnectAsync after Dispose; cancel any pending reconnect task before disposing.
- Create a fresh GarnetClientSession instead of reconnecting a disposed one — Reconnect is for live sessions, not resurrected ones.
- Guard the reconnect call site with a disposed flag or ObjectDisposedException handling.
Example fix
// before
session.ReconnectAsync();
// after — create a new session if the old one is disposed
if (session.Disposed)
session = new GarnetClientSession(endpoint, ...);
await session.ConnectAsync(); Defensive patterns
Strategy: validation
Validate before calling
if (session is null) throw new ArgumentNullException(nameof(session)); if (session.Disposed) throw new ObjectDisposedException(nameof(GarnetClientSession));
Type guard
if (session?.Disposed ?? true) { /* create a new session instead */ } Try / catch
try { await session.ReconnectAsync(); }
catch (ObjectDisposedException) { session = new GarnetClientSession(endpoint, ...); await session.ConnectAsync(); } Prevention
- Cancel pending reconnect tasks before disposing a session.
- Create a fresh session rather than reconnecting a disposed one.
- Track lifecycle explicitly so no caller touches a disposed session.
When it happens
Trigger: Calling ReconnectAsync on a GarnetClientSession after Dispose() (or DisposeAsync) has already run; a retry/reconnect loop that runs after the owning pool or application has torn the session down.
Common situations: A reconnect-on-failure policy that outlives the application shutdown; disposing in a finally block but an outstanding reconnect task still fires; using a session from an AsyncPool that was disposed while a reconnect was queued.
Related errors
- Failed to connect at {EndPoint}
- Payload length {payloadLength} is larger than bufferSize {ne
- Unexpected response: {response}]
- Failed to connect at {EndPoint}
- LightEpoch
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/e06b33c6078e7cfc.
Report an issue: GitHub.