{"record":{"id":"a75e56bbc281958c","repo":"github/copilot-sdk","slug":"failed-to-disconnect-session-w","errorCode":null,"errorMessage":"failed to disconnect session: %w","messagePattern":"failed to disconnect session: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/session.go","lineNumber":1878,"sourceCode":"\n\ts.toolHandlersM.Lock()\n\ts.toolHandlers = nil\n\ts.toolHandlersM.Unlock()\n\n\ts.permissionMux.Lock()\n\ts.permissionHandler = nil\n\ts.permissionMux.Unlock()\n\n\ts.commandHandlersMu.Lock()\n\ts.commandHandlers = nil\n\ts.commandHandlersMu.Unlock()\n\n\ts.elicitationMu.Lock()\n\ts.elicitationHandler = nil\n\ts.elicitationMu.Unlock()\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to disconnect session: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (s *Session) releaseGitHubTokenProviderRegistration() {\n\ts.gitHubTokenProviderMu.Lock()\n\tif s.gitHubTokenProviderReleased {\n\t\ts.gitHubTokenProviderMu.Unlock()\n\t\treturn\n\t}\n\ts.gitHubTokenProviderReleased = true\n\trelease := s.releaseGitHubTokenProvider\n\ts.releaseGitHubTokenProvider = nil\n\ts.gitHubTokenProviderMu.Unlock()\n\tif release != nil {\n\t\trelease()\n\t}\n}","sourceCodeStart":1860,"sourceCodeEnd":1896,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/session.go#L1860-L1896","documentation":"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.","triggerScenarios":"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.","commonSituations":"Runtime process already dead so detach cannot be delivered; session already torn down server-side; version skew producing an undecodable detach response.","solutions":["Inspect the wrapped cause to distinguish transport failure vs server-reported error","If the runtime is already gone, treat disconnect failure as benign and close the client locally","Retry Disconnect once after confirming the runtime is reachable","Recreate the session if server state is irrecoverable"],"exampleFix":"// before\nif err := session.Disconnect(); err != nil { panic(err) }\n// after\nif err := session.Disconnect(); err != nil {\n    log.Printf(\"disconnect: %v (continuing local cleanup)\", err)\n}","handlingStrategy":"try-catch","validationCode":"if session == nil || session.SessionID == \"\" {\n    return nil // nothing to disconnect\n}","typeGuard":null,"tryCatchPattern":"if err := session.Disconnect(); err != nil {\n    // teardown is best-effort; log and continue\n    log.Printf(\"disconnect: %v\", err)\n}","preventionTips":["Call Disconnect before abandoning a session","Treat disconnect errors as non-fatal during shutdown","Check whether the runtime process is alive to interpret the cause"],"tags":["go","session","rpc","lifecycle"],"backgroundTag":"api-request-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}