Title: Stop detaches the debugger before shutdown hooks run, so JVM shutdown cannot be debugged · Issue #1720 · microsoft/vscode-java-debug · GitHub
Open Graph Title: Stop detaches the debugger before shutdown hooks run, so JVM shutdown cannot be debugged · Issue #1720 · microsoft/vscode-java-debug
X Title: Stop detaches the debugger before shutdown hooks run, so JVM shutdown cannot be debugged · Issue #1720 · microsoft/vscode-java-debug
Description: Since #1274 / microsoft/java-debug#579, pressing Stop on a launched Java program (with "console": "internalConsole") sends SIGTERM through vm.process().destroy(), so shutdown hooks now run. However, the debugger detaches immediately afte...
Open Graph Description: Since #1274 / microsoft/java-debug#579, pressing Stop on a launched Java program (with "console": "internalConsole") sends SIGTERM through vm.process().destroy(), so shutdown hooks now run. However...
X Description: Since #1274 / microsoft/java-debug#579, pressing Stop on a launched Java program (with "console": "internalConsole") sends SIGTERM through vm.process().destroy(), so shutdown ho...
Opengraph URL: https://github.com/microsoft/vscode-java-debug/issues/1720
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Stop detaches the debugger before shutdown hooks run, so JVM shutdown cannot be debugged","articleBody":"Since #1274 / microsoft/java-debug#579, pressing **Stop** on a launched Java program (with `\"console\": \"internalConsole\"`) sends SIGTERM through `vm.process().destroy()`, so shutdown hooks now run. However, the debugger detaches immediately afterwards, so breakpoints in shutdown hooks, `@PreDestroy` methods, Spring `SmartLifecycle.stop()`, etc. are never hit. As a result, the shutdown path of an application cannot be debugged from VS Code.\n\nThis is not a duplicate of #1274, #1585 or #1705. Those issues are about whether the JVM is terminated and whether the hooks run at all. This one is about the debug session staying attached while they run.\n\n##### Environment\n- Operating System: Linux Mint 22.1\n- JDK version: 21.0.7\n- Visual Studio Code version: 1.143.0\n- Java extension version: 1.59.2026102108 (pre-release)\n- Java Debugger extension version: 0.60.0\n\n##### Steps To Reproduce\n1. Create a program:\n ```java\n public class App {\n public static void main(String[] args) throws Exception {\n Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n System.out.println(\"hook start\"); // breakpoint here\n System.out.println(\"hook end\");\n }));\n Thread.sleep(Long.MAX_VALUE);\n }\n }\n ```\n2. Launch it with a `launch` configuration with `\"console\": \"internalConsole\"`.\n3. Set a breakpoint on the `hook start` line.\n4. Press **Stop**.\n\n##### Current Result\nThe debug session ends immediately. The hook runs (`hook start` / `hook end` may or may not reach the Debug Console), but the breakpoint is not hit.\n\n##### Expected Result\nThe first **Stop** asks the JVM to exit gracefully and keeps the debugger attached, so breakpoints in shutdown code are hit. The session ends when the JVM exits (VMDeath/VMDisconnect). A second **Stop** forcibly kills the JVM, as it does now. IntelliJ IDEA and Eclipse behave this way.\n\n##### Additional Informations\nCause: [`DisconnectRequestHandler.destroyDebugSession`](https://github.com/microsoft/java-debug/blob/main/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/DisconnectRequestHandler.java) does `terminate()` and then `detach()` in a `finally` block. `Process.destroy()` only sends the signal and does not wait for the process, so the debugger is gone before the hooks start. (Before microsoft/java-debug#626 the order was reversed explicitly.)\n\nDAP already supports this two-step behaviour through the [`terminate` request](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Terminate). If the adapter reports `supportsTerminateRequest: true`, VS Code sends `terminate` on the first Stop and `disconnect` on the next one. A possible implementation:\n\n- report `supportsTerminateRequest` in the `initialize` response;\n- handle `terminate` with `vm.process().destroy()` (when a `Process` is available) and do **not** detach; the existing VMDeath/VMDisconnect handling then sends `terminated` and ends the session;\n- keep the current `disconnect` behaviour (forced termination) for the second Stop and for restart.\n\nI have checked this approach locally with a small extension. It uses a `DebugAdapterTracker` to add `supportsTerminateRequest`, sends SIGTERM to the PID from the `processid` event, and lets the JVM exit on its own. With it, breakpoints in shutdown hooks are hit, and the session closes when the JVM exits.\n\nWith `\"console\": \"integratedTerminal\"` the adapter has no `Process` and falls back to `vm.exit(0)`, so the hooks do not run at all. That case may need the PID from the `runInTerminal` response, and could be handled separately.","author":{"url":"https://github.com/danilaslynko","@type":"Person","name":"danilaslynko"},"datePublished":"2026-10-22T11:11:27Z","url":"https://github.com/microsoft/vscode-java-debug/issues/1720"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:1ec3c28b-55dd-9102-4fe0-d9bab3e84527 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | C1E2:3BDB91:18612CF:223112D:6AF7CC30 |
| html-safe-nonce | 14e1af22f650090d5614ff4e89cb8d8c931317866d85c47bce9f1ea6a9fc4bf2 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDMUUyOjNCREI5MToxODYxMkNGOjIyMzExMkQ6NkFGN0NDMzAiLCJ2aXNpdG9yX2lkIjoiNzA1Nzg2Mjc3Nzk4MDMwODUyOCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 26c613a2c746003dbd348f0c0a07d4045cd1b3ef56728e8066a1d34b43c827ea |
| hovercard-subject-tag | issue:5978177183 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/microsoft/vscode-java-debug/1720/issue_layout |
| twitter:image | https://opengraph.githubassets.com/e1426901d9cf3023d6a4702f3379d553310439b5ebebfb0241dd065172fe1740/microsoft/vscode-java-debug/issues/1720 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/e1426901d9cf3023d6a4702f3379d553310439b5ebebfb0241dd065172fe1740/microsoft/vscode-java-debug/issues/1720 |
| og:image:alt | Since #1274 / microsoft/java-debug#579, pressing Stop on a launched Java program (with "console": "internalConsole") sends SIGTERM through vm.process().destroy(), so shutdown hooks now run. However... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | danilaslynko |
| hostname | github.com |
| expected-hostname | github.com |
| None | 0538a59d4a0acd1aee7d41f7f56bd94b5294b4b7cb8ac3a11a32ac8bb4562076 |
| turbo-cache-control | no-preview |
| go-import | github.com/microsoft/vscode-java-debug git https://github.com/microsoft/vscode-java-debug.git |
| octolytics-dimension-user_id | 6154722 |
| octolytics-dimension-user_login | microsoft |
| octolytics-dimension-repository_id | 102584737 |
| octolytics-dimension-repository_nwo | microsoft/vscode-java-debug |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 102584737 |
| octolytics-dimension-repository_network_root_nwo | microsoft/vscode-java-debug |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 8a34a01748011ac03e602fdd18a9597dd6341074 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width