github/copilot-sdk · error
WebSocket response bridge is not attached
Error message
WebSocket response bridge is not attached
What it means
CopilotRequestHandler's protected constructor requires a WebSocket response bridge to have been attached to the CopilotRequestContext under the internal kBridge symbol. The bridge is what carries responses back to the runtime over the WebSocket RPC channel. If it is missing, the handler cannot emit responses, so construction fails immediately.
Solutions
- Do not construct request handlers yourself; let the Copilot runtime create them and only implement the handler entry points.
- If subclassing, pass through the exact context object given to your handler factory/callback, never a hand-built context object.
- In tests, use the SDK's provided test harness/factory that attaches the internal bridge rather than constructing the handler directly.
- Align SDK versions so the runtime attaching the bridge and the handler reading kBridge are the same package version.
Example fix
// before
const ctx = { requestId: 'r1' } as CopilotRequestContext;
const handler = new MyHandler(ctx); // throws: no bridge
// after
export default createRequestHandler((ctx) => new MyHandler(ctx)); // runtime-attached context Defensive patterns
Strategy: validation
Validate before calling
function canCreateHandler(ctx: unknown): ctx is CopilotRequestContext {
return !!ctx && typeof ctx === 'object' && !!(ctx as Partial<InternalContext>)[kBridge];
}
if (!canCreateHandler(ctx)) throw new Error('context lacks WebSocket response bridge'); Type guard
const isAttachableContext = (c: unknown): c is CopilotRequestContext & { [kBridge]?: unknown } =>
typeof c === 'object' && c !== null; Try / catch
try {
const handler = new MyHandler(ctx);
} catch (e) {
if (e instanceof Error && e.message.includes('bridge is not attached')) {
// context not runtime-provided; fix construction site
}
throw e;
} Prevention
- Never construct request handlers manually; use the runtime's handler factory/registration API.
- Pass through the runtime-provided context object unchanged to super().
- In tests, use the SDK harness that attaches the internal bridge.
- Keep SDK package versions aligned between runtime and extension.
When it happens
Trigger: Calling the protected CopilotRequestHandler constructor (directly or from a subclass via super(context)) with a context object created outside the runtime's request-dispatch path, so no bridge was attached under kBridge.
Common situations: Subclassing CopilotRequestHandler and instantiating it manually in tests or scripts with a plain/partial context instead of receiving the runtime-provided context; using an older/newer SDK version where the internal bridge key or attachment mechanism changed.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- WebSocket response bridge is not attached.
- WebSocket response bridge is not attached
- Copilot request was cancelled by the runtime.
- Copilot request response used after RPC connection closed.
- Client not connected. Call start() first.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/bc4d087647779c90.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/copilotRequestHandler.ts:85
* forwarding traffic to the real upstream, subclass {@link CopilotWebSocketForwarder}
* instead, which connects upstream and forwards by default.
*
* @experimental
*/
export abstract class CopilotWebSocketHandler implements AsyncDisposable {
readonly #response: CopilotWebSocketResponseBridge;
readonly #completion: Promise<CopilotWebSocketCloseStatus>;
#resolveCompletion!: (status: CopilotWebSocketCloseStatus) => void;
#closed = false;
[kSuppressCloseOnDispose] = false;
protected readonly context: CopilotRequestContext;
protected constructor(context: CopilotRequestContext) {
this.context = context;
const bridge = (context as Partial<InternalContext>)[kBridge];
if (!bridge) {
throw new Error("WebSocket response bridge is not attached");
}
this.#response = bridge;
this.#completion = new Promise<CopilotWebSocketCloseStatus>((resolve) => {
this.#resolveCompletion = resolve;
});
}
async sendResponseMessage(data: string | Uint8Array): Promise<void> {
await this.#response.write(data);
}
async close(
status: CopilotWebSocketCloseStatus = CopilotWebSocketCloseStatus.normalClosure
): Promise<void> {
if (this.#closed) {
return;
}
this.#closed = true;View on GitHub (pinned to cd8cf15dc3)