github/copilot-sdk · error · InvalidOperationException
WebSocket response bridge is not attached.
Error message
WebSocket response bridge is not attached.
What it means
CopilotWebSocketHandler's constructor requires the CopilotRequestContext to carry a WebSocket response bridge used to deliver responses upstream. This InvalidOperationException is thrown at handler construction when context.WebSocketResponse is null, meaning the handler cannot send anything back.
Solutions
- Attach the WebSocket response bridge to the CopilotRequestContext before constructing the handler (context.WebSocketResponse = ...)
- Use the library's factory/context-builder methods instead of hand-constructing CopilotRequestContext
- Check for a version mismatch where your transport predates the WebSocketResponse property
Example fix
// before
var handler = new MyHandler(new CopilotRequestContext { WebSocket = ws });
// after
var handler = new MyHandler(new CopilotRequestContext { WebSocket = ws, WebSocketResponse = bridge }); Defensive patterns
Strategy: validation
Validate before calling
if (context.WebSocketResponse is null) throw new InvalidOperationException("Attach WebSocketResponse bridge before creating the handler"); Type guard
static bool BridgeAttached(CopilotRequestContext ctx) => ctx.WebSocketResponse is not null;
Try / catch
try { var handler = new MyHandler(context); }
catch (InvalidOperationException ex) when (ex.Message.Contains("response bridge")) { /* fix context wiring */ } Prevention
- Always construct CopilotRequestContext through the library's builders
- Never hand-roll request contexts in custom transports
- Re-check context wiring after upgrading the library
When it happens
Trigger: Constructing a derived CopilotWebSocketHandler with a CopilotRequestContext whose WebSocketResponse bridge was never attached (e.g. context built manually or by a transport that skipped bridge wiring).
Common situations: Custom transport implementations create request contexts without calling the bridge-attachment step; testing code constructs contexts by hand; an upgrade changed how the bridge is attached to the context.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- WebSocket response bridge is not attached
- FfiRuntimeHost has not been started.
- WebSocket response bridge is not attached
- Copilot request was cancelled by the runtime.
- Copilot request response used after RPC connection closed.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/f383c6876c96a38a.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/CopilotRequestHandler.cs:168
public abstract class CopilotWebSocketHandler : IAsyncDisposable
{
private readonly TaskCompletionSource<CopilotWebSocketCloseStatus> _completion =
new(TaskCreationOptions.RunContinuationsAsynchronously);
private int _closed;
private bool _suppressCloseOnDispose;
/// <summary>Request context for this WebSocket connection.</summary>
protected CopilotRequestContext Context { get; }
internal Task<CopilotWebSocketCloseStatus> Completion => _completion.Task;
/// <summary>
/// Initializes a per-connection handler for the supplied request context.
/// </summary>
protected CopilotWebSocketHandler(CopilotRequestContext context)
{
Context = context;
_ = context.WebSocketResponse ?? throw new InvalidOperationException("WebSocket response bridge is not attached.");
}
/// <summary>
/// Send a message from the runtime to the upstream connection.
/// </summary>
public abstract Task SendRequestMessageAsync(CopilotWebSocketMessage message);
/// <summary>
/// Send a message from the upstream connection back to the runtime.
/// Override to mutate or duplicate messages; call <c>base</c> to emit.
/// </summary>
public virtual Task SendResponseMessageAsync(CopilotWebSocketMessage message) =>
Context.WebSocketResponse!.WriteAsync(message);
/// <summary>
/// Close the connection and finalise the runtime-facing response.
/// </summary>
public virtual async Task CloseAsync(CopilotWebSocketCloseStatus status)View on GitHub (pinned to cd8cf15dc3)