stride3d/stride · error · IOException
Socket closed
Error message
Socket closed
What it means
SocketExtensions.ReadAllAsync loops until the requested number of bytes is read; a ReadAsync returning 0 means the remote end closed the stream, so it throws IOException("Socket closed"). It guards callers from treating a clean close as end-of-protocol.
Solutions
- Wrap socket reads in try-catch for IOException and treat it as a disconnection (reconnect).
- Check the remote endpoint's health/logs to see why the connection closed.
- Keep the connection alive (heartbeats) or set timeouts consistent between peers.
- Verify message framing matches on both sides so reads don't over-read and hit the close.
Example fix
// before
var value = await stream.ReadStringAsync(); // throws when peer closed
// after
string value;
try { value = await stream.ReadStringAsync(); }
catch (IOException) { Reconnect(); return; } Defensive patterns
Strategy: try-catch
Try / catch
try { var s = await stream.ReadStringAsync(); }
catch (IOException) { HandleDisconnect(); } Prevention
- Treat IOException on reads as a disconnect signal and reconnect.
- Add heartbeats/idle timeouts consistent between both peers.
- Match message framing on both ends to avoid over-reading a closing stream.
When it happens
Trigger: Reading from a TCP stream whose remote peer closed the connection before delivering all requested bytes — ReadAsync returns 0 inside ReadAllAsync (used by ReadStringAsync and other helpers).
Common situations: Server crash or restart mid-message; remote host closed socket due to timeout or firewall idle cutoff; client reading a response after the server finished and disposed the socket.
Related errors
- Could not connect to server
- Connection router did not connect back to our listen socket
- Invalid ack
- Cannot listen on an unusable interface. Check the IsUsable…
- File doesn't appear to be a valid package
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/f123a53017e0a9d3.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Engine/Engine/Network/SocketExtensions.cs:18
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.IO;
using System.Threading.Tasks;
namespace Stride.Engine.Network
{
public static class SocketExtensions
{
public static async Task ReadAllAsync(this Stream socket, byte[] buffer, int offset, int size)
{
while (size > 0)
{
int read = await socket.ReadAsync(buffer, offset, size).ConfigureAwait(false);
if (read == 0)
throw new IOException("Socket closed");
size -= read;
offset += read;
}
}
public static async Task WriteInt32Async(this Stream socket, int value)
{
var buffer = BitConverter.GetBytes(value);
await socket.WriteAsync(buffer, 0, sizeof(int)).ConfigureAwait(false);
}
public static async Task<int> ReadInt32Async(this Stream socket)
{
var buffer = new byte[sizeof(int)];
await socket.ReadAllAsync(buffer, 0, sizeof(int)).ConfigureAwait(false);
return BitConverter.ToInt32(buffer, 0);
}
View on GitHub (pinned to 96fad776d2)