github/copilot-sdk · error
Failed to disconnect session
Error message
Failed to disconnect session ${this.sessionId}: ${response.error || "Unknown error"} What it means
Thrown during disconnect() when the `session.detach` request (retried up to twice) still reports success:false. The message includes the session id and the error string returned by the host, or "Unknown error" when the response carries no error detail. The session is not marked disconnected in this path.
Solutions
- Inspect response.error in the message to see the host-side detach failure and fix that root cause
- Retry disconnect() after a short delay — the SDK only retries twice
- Check that the connection is still alive before disconnecting; reconnect if the transport dropped
- Treat an already-disconnected session as success and skip detach
Example fix
// before
await session.disconnect(); // throws if host reports failure twice
// after
try {
await session.disconnect();
} catch (err) {
if (!session.isDisconnected) {
await new Promise((r) => setTimeout(r, 1000));
await session.disconnect();
}
} Defensive patterns
Strategy: retry
Validate before calling
if (!session.isConnected || session.isDisconnected) return; // nothing to detach if (session.disconnecting) return; // avoid concurrent disconnects
Try / catch
try {
await session.disconnect();
} catch (err) {
if (String(err?.message).startsWith("Failed to disconnect session")) {
console.warn(`Detach failed: ${err.message}; forcing local cleanup`);
session.forceCleanup?.();
} else throw err;
} Prevention
- Use a disconnect mutex/flag to prevent concurrent disconnect calls
- Check connection health before detaching and reconnect if the transport dropped
- Log response.error from the throw message to fix host-side detach failures
When it happens
Trigger: Host returns { success: false, error } from session.detach on both attempts; connection-level failure so detach never succeeds; session already torn down server-side with an error status.
Common situations: Flaky or dropped transport mid-disconnect; server busy/restarting during shutdown; calling disconnect concurrently from multiple code paths so the second call detaches an already-detached session and errors.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/4124bcd5c26aa7bc.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:2081
* ```typescript
* // Clean up when done — session can still be resumed later
* await session.disconnect();
* ```
*/
async disconnect(): Promise<void> {
if (this.disconnected || this.disconnecting) {
return;
}
this.disconnecting = true;
try {
let response: { success: boolean; error?: string } = { success: false };
for (let attempt = 0; attempt < 2 && !response.success; attempt++) {
response = (await this.connection.sendRequest("session.detach", {
sessionId: this.sessionId,
})) as { success: boolean; error?: string };
}
if (!response.success) {
throw new Error(
`Failed to disconnect session ${this.sessionId}: ${response.error || "Unknown error"}`
);
}
this._markDisconnected();
} catch (error) {
this.disconnecting = false;
throw error;
}
}
/** Enables `await using session = ...` syntax for automatic cleanup. */
async [Symbol.asyncDispose](): Promise<void> {
return this.disconnect();
}
/**
* Aborts the currently processing message in this session.
*View on GitHub (pinned to cd8cf15dc3)