github/copilot-sdk · critical · IOException
Communication error with Copilot CLI
Error message
Communication error with Copilot CLI: {ex.Message} What it means
Thrown as IOException when a generic (non-RPC-protocol) communication exception occurs while talking to the Copilot CLI and no stderr output was captured. The original exception message is embedded so the underlying cause (stream closed, pipe broken, etc.) is visible, and it is wrapped as the inner exception.
Solutions
- Check the InnerException for the true transport failure
- Verify the CLI process is still alive (IsAlive/process handle) and restart the client/connection if not
- Add retry logic around transient RPC calls with a new client instance on failure
- Capture the CLI's own logs to find why the transport broke; upgrade the CLI if it crashes silently
Example fix
// before
var resp = await client.SendAsync(req);
// after
try { var resp = await client.SendAsync(req); }
catch (IOException ex) when (ex.InnerException is not null) { logger.LogWarning(ex.InnerException, "transport failure"); await RestartClientAsync(); } Defensive patterns
Strategy: retry
Validate before calling
if (!client.IsConnected) { client = await ReconnectAsync(); } Try / catch
try { return await client.SendAsync(req); }
catch (IOException ex) when (IsTransient(ex)) { await Task.Delay(backoff); return await RetryWithNewClientAsync(req); } Prevention
- Wrap long-lived clients with health checks and automatic reconnect
- Use retry with backoff for idempotent RPCs
- Preserve InnerException when logging
- Keep CLI process from being killed (resource limits, signals)
When it happens
Trigger: An IOException (or similar communication exception) occurs during an RPC call while the CLI process is running or its stderr is empty — e.g. the stdio pipe/transport broke mid-request without the process printing anything.
Common situations: CLI process killed abruptly (SIGKILL) without flushing stderr; broken pipe when the OS terminated the child; transport deserialization/handler exceptions surfaced as communication errors.
Related errors
- CLI process exited unexpectedly. stderr
- CLI process exited unexpectedly.
- Invalid value ' '. Expected 'inprocess', 'stdio', or unset.
- Runtime process not started
- Runtime process exited unexpectedly
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/a85edbdf8eeeaa41.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/Client.cs:1976
return await rpc.InvokeAsync<T>(method, args, cancellationToken, onResponseInline);
}
catch (ConnectionLostException ex)
{
string? stderrOutput = null;
if (stderrBuffer is not null)
{
lock (stderrBuffer)
{
stderrOutput = stderrBuffer.ToString().Trim();
}
}
if (!string.IsNullOrEmpty(stderrOutput))
{
throw new IOException(FormatCliExitedMessage("CLI process exited unexpectedly.", stderrOutput!), ex);
}
throw new IOException($"Communication error with Copilot CLI: {ex.Message}", ex);
}
catch (RemoteRpcException ex)
{
throw new IOException($"Communication error with Copilot CLI: {ex.Message}", ex);
}
}
private static string FormatCliExitedMessage(string message, string stderrOutput)
{
return string.IsNullOrEmpty(stderrOutput)
? message
: $"{message}\nstderr: {stderrOutput}";
}
[LoggerMessage(
Level = LogLevel.Information,
Message = "CopilotClient.StartCliServerAsync starting Copilot CLI. CliPath={CliPath}, Executable={Executable}, CliPathSource={CliPathSource}, UseStdio={UseStdio}, Port={Port}")]
private static partial void LogStartingCopilotCli(ILogger logger, string cliPath, string executable, string cliPathSource, bool useStdio, int? port);View on GitHub (pinned to cd8cf15dc3)