github/copilot-sdk · error

failed to disconnect session

Error message

failed to disconnect session: %w

What it means

Session.Disconnect cleans up in-memory handlers and, before that, the detach RPC (or the decode of its response) may fail; any such error is re-wrapped as "failed to disconnect session". It signals the runtime refused or could not complete the detach, so server-side session resources may not have been released.

Solutions

  1. Inspect the wrapped cause to distinguish transport failure vs server-reported error
  2. If the runtime is already gone, treat disconnect failure as benign and close the client locally
  3. Retry Disconnect once after confirming the runtime is reachable
  4. Recreate the session if server state is irrecoverable

Example fix

// before
if err := session.Disconnect(); err != nil { panic(err) }
// after
if err := session.Disconnect(); err != nil {
    log.Printf("disconnect: %v (continuing local cleanup)", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if session == nil || session.SessionID == "" {
    return nil // nothing to disconnect
}

Try / catch

if err := session.Disconnect(); err != nil {
    // teardown is best-effort; log and continue
    log.Printf("disconnect: %v", err)
}

Prevention

When it happens

Trigger: Calling Session.Disconnect() when the underlying `session.detach` request errors, its response fails to decode, or the server reports response.Success == false with an error message.

Common situations: Runtime process already dead so detach cannot be delivered; session already torn down server-side; version skew producing an undecodable detach response.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/a75e56bbc281958c. Report an issue: GitHub.

Appendix: source

Thrown at go/session.go:1878

	s.toolHandlersM.Lock()
	s.toolHandlers = nil
	s.toolHandlersM.Unlock()

	s.permissionMux.Lock()
	s.permissionHandler = nil
	s.permissionMux.Unlock()

	s.commandHandlersMu.Lock()
	s.commandHandlers = nil
	s.commandHandlersMu.Unlock()

	s.elicitationMu.Lock()
	s.elicitationHandler = nil
	s.elicitationMu.Unlock()

	if err != nil {
		return fmt.Errorf("failed to disconnect session: %w", err)
	}
	return nil
}

func (s *Session) releaseGitHubTokenProviderRegistration() {
	s.gitHubTokenProviderMu.Lock()
	if s.gitHubTokenProviderReleased {
		s.gitHubTokenProviderMu.Unlock()
		return
	}
	s.gitHubTokenProviderReleased = true
	release := s.releaseGitHubTokenProvider
	s.releaseGitHubTokenProvider = nil
	s.gitHubTokenProviderMu.Unlock()
	if release != nil {
		release()
	}
}

View on GitHub (pinned to cd8cf15dc3)