{"record":{"id":"e4425fafcf6fe621","repo":"github/copilot-sdk","slug":"failed-to-decode-session-detach-response-w","errorCode":null,"errorMessage":"failed to decode session detach response: %w","messagePattern":"failed to decode session detach response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/session.go","lineNumber":1841,"sourceCode":"// session data including files on disk, use [Client.DeleteSession] instead.\n//\n// After calling this method, the session object can no longer be used.\n//\n// Returns an error if the connection fails.\n//\n// Example:\n//\n//\t// Clean up when done — session can still be resumed later\n//\tif err := session.Disconnect(); err != nil {\n//\t    log.Printf(\"Failed to disconnect session: %v\", err)\n//\t}\nfunc (s *Session) Disconnect() error {\n\ts.cancelPendingExternalTools()\n\tresult, err := s.client.Request(context.Background(), \"session.detach\", sessionDetachRequest{SessionID: s.SessionID})\n\tif err == nil {\n\t\tvar response sessionDetachResponse\n\t\tif decodeErr := json.Unmarshal(result, &response); decodeErr != nil {\n\t\t\terr = fmt.Errorf(\"failed to decode session detach response: %w\", decodeErr)\n\t\t} else if !response.Success {\n\t\t\tif response.Error == \"\" {\n\t\t\t\tresponse.Error = \"unknown error\"\n\t\t\t}\n\t\t\terr = errors.New(response.Error)\n\t\t}\n\t}\n\n\t// Local cleanup always runs, even if the detach RPC failed, so callers\n\t// don't leak in-memory resources (event goroutines, registered\n\t// providers/handlers) just because the runtime couldn't be reached.\n\ts.stopEventProcessing()\n\ts.releaseGitHubTokenProviderRegistration()\n\n\t// Clear handlers\n\ts.handlerMutex.Lock()\n\ts.handlers = nil\n\ts.handlerMutex.Unlock()","sourceCodeStart":1823,"sourceCodeEnd":1859,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/session.go#L1823-L1859","documentation":"Session.Disconnect sends the `session.detach` RPC; on success it unmarshals the result into sessionDetachResponse. This error means the detach response JSON could not be decoded — the runtime's reply does not match the SDK's expected `{success, error}` shape.","triggerScenarios":"Calling Session.Disconnect() when `session.detach` returns a payload that fails json.Unmarshal into sessionDetachResponse (wrong field types or unexpected schema).","commonSituations":"Version skew between SDK and runtime changing the detach response; a non-standard runtime build returning a different detach payload; truncated/corrupt response.","solutions":["Align SDK and runtime versions (upgrade both)","Capture the raw detach response to compare against the expected shape","Retry Disconnect once; if it persists, close the underlying client connection instead","File an issue with the raw payload if versions already match"],"exampleFix":"// before\nif err := session.Disconnect(); err != nil { log.Fatal(err) }\n// after\nif err := session.Disconnect(); err != nil {\n    log.Printf(\"detach decode failed, forcing client close: %v\", err)\n    _ = client.Close()\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := session.Disconnect(); err != nil {\n    if strings.Contains(err.Error(), \"decode session detach\") {\n        _ = client.Close() // fall back to local teardown\n    } else {\n        return err\n    }\n}","preventionTips":["Match SDK and runtime versions","Never assume detach succeeded without checking err","Have a local-cleanup fallback for teardown paths"],"tags":["go","json","unmarshal","session"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}