You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
In-process (.NET, Windows): access violation in copilot_runtime_connection_write when responding to runtime requests #2821
With in-process hosting (RuntimeConnection.ForInProcess()) on Windows x64, the host process dies with an access violation (0xC0000005) inside the native copilot_runtime_connection_write while the .NET SDK writes a response frame. It happens mid-turn in long agent sessions and takes down the whole host application.
Versions
GitHub.Copilot.SDK 1.0.16 (runtime 1.0.89) and 1.0.17 (runtime 1.0.93); reproduced on both
Session config: OnPreToolUse hook (synchronous, returns allow), OnPermissionRequest handler (synchronous allow), OnUserInputRequest, OnElicitationRequest, an HTTP MCP server with many tools, AskUserVariant.Elicitation, a custom provider pointed at a loopback HTTP endpoint
Stack (1.0.17)
Fatal error.
0xC0000005
at GitHub.Copilot.FfiRuntimeHost.<ConnectionWrite>g____PInvoke|55_0(UInt32, Byte*, UIntPtr)
at GitHub.Copilot.FfiRuntimeHost.SendFrame(System.ReadOnlySpan`1<Byte>)
at GitHub.Copilot.JsonRpc+<SendMessageAsync>d__35`1[[System.__Canon, ...]].MoveNext()
at GitHub.Copilot.JsonRpc+<SendResultResponseAsync>d__46.MoveNext()
at GitHub.Copilot.JsonRpc.SendResultResponseAsync(System.Text.Json.JsonElement, System.Object, System.Type, System.Threading.CancellationToken)
at GitHub.Copilot.JsonRpc+<HandleIncomingMethodAsync>d__41.MoveNext()
at GitHub.Copilot.JsonRpc+<ReadLoopAsync>d__37.MoveNext()
...
at GitHub.Copilot.JsonRpc+<ReadMessageAsync>d__39.MoveNext()
...
at GitHub.Copilot.FfiRuntimeHost+CallbackReceiveStream+<ReadAsync>d__4.MoveNext()
...
at GitHub.Copilot.FfiRuntimeHost+CallbackReceiveStream+<ReadCoreAsync>d__5.MoveNext()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()
On 1.0.16 the same fault came through JsonRpc.SendMessageAsync from CopilotSession.HandlePendingPermissionRequestAsync.
Pattern
Both crashes happened right after the model issued two MCP tool calls in parallel. The host log shows two preToolUse approvals, then two permission-request approvals, then an MCP HTTP call returning 200, and then the fault while writing a response frame back to the runtime. FfiRuntimeHost.SendFrame already holds _lifecycleLock and checks _disposed and _connectionId, so the managed side does not seem to be writing concurrently or after close. The fault appears to be in the native write path.
Frequency: about 1 crash in 15–20 multi-tool conversations when replaying real user sessions (each 1–4 turns, 10–60 tool calls). Single-turn tests and a 40-turn sequential stress run did not reproduce it, so concurrency between parallel tool calls looks like a factor.
Possibly related: on 1.0.16 we also saw one turn hang forever. The session's events.jsonl had hook.start for preToolUse with no matching hook.end, even though our hook returns synchronously.
Expected
A response write to an open connection either succeeds or fails with a managed error. It should never crash the host process.
Happy to run a build with extra native logging if that helps.
Thanks for the detailed report. I labeled this bug.
What I checked (dotnet/src/FfiRuntimeHost.cs, dotnet/src/JsonRpc.cs):
JsonRpc.SendMessageAsync serializes every write behind _writeLock. It builds one pooled frame and holds the buffer until the write returns.
FfiRuntimeHost.SendFrame takes _lifecycleLock, checks _disposed and _connectionId, and then calls copilot_runtime_connection_write with the frame span. The span is pinned for the duration of the call, and the code assumes the native side copies it before returning.
CallbackSendStream just forwards to SendFrame. It has no async gap between the buffer being rented and the write.
Findings: I couldn't find a managed-side race. Writes are serialized, they are not issued after dispose or close, and the buffer outlives the call. That matches your reading that the fault is in the native write path, probably when a write overlaps native work triggered by the parallel tool calls. The native runtime isn't built from this repo, so I couldn't reproduce or root-cause it here. A write to an open connection should return failure, which the SDK surfaces as an IOException. It shouldn't take the process down.
Next steps:
Native logging or a crash dump (the faulting address and the native stack above copilot_runtime_connection_write) would help the runtime team. The failing write's frame length would also help.
A repro that issues two parallel MCP tool calls with the pre-tool-use hook and permission handlers would help too.
The missing hook.end for preToolUse on 1.0.16 may be a separate issue. Please file it separately if it recurs on 1.0.17.
Generated by Bug Handler for #2821 · copilot · auto · 18 AIC · ⌖ 0.522 AIC · ⊞ 7.5K · ◷
Activity
github-actions commentedon Oct 8, 2026
Thanks for the detailed report. I labeled this
bug.What I checked (
dotnet/src/FfiRuntimeHost.cs,dotnet/src/JsonRpc.cs):JsonRpc.SendMessageAsyncserializes every write behind_writeLock. It builds one pooled frame and holds the buffer until the write returns.FfiRuntimeHost.SendFrametakes_lifecycleLock, checks_disposedand_connectionId, and then callscopilot_runtime_connection_writewith the frame span. The span is pinned for the duration of the call, and the code assumes the native side copies it before returning.CallbackSendStreamjust forwards toSendFrame. It has no async gap between the buffer being rented and the write.Findings: I couldn't find a managed-side race. Writes are serialized, they are not issued after dispose or close, and the buffer outlives the call. That matches your reading that the fault is in the native write path, probably when a write overlaps native work triggered by the parallel tool calls. The native runtime isn't built from this repo, so I couldn't reproduce or root-cause it here. A write to an open connection should return failure, which the SDK surfaces as an
IOException. It shouldn't take the process down.Next steps:
copilot_runtime_connection_write) would help the runtime team. The failing write's frame length would also help.hook.endforpreToolUseon 1.0.16 may be a separate issue. Please file it separately if it recurs on 1.0.17.