Documentation
Everything needed to install CatchMe and read what it tells you. The commands and settings tables below are generated from the extension manifest at build time, so they cannot drift from what ships.
Install
From inside Visual Studio Code, open the Extensions view and search for CatchMe, or run this from the Command Palette (Ctrl/Cmd+P):
ext install leplusorg.catchme
It is also on the Visual Studio Code Marketplace and
Open VSX for VSCodium, Gitpod and Cursor. Requires Visual Studio Code
^1.90.0 or later.
Language support
| Language | You also need | Answers are |
|---|---|---|
| Java | Language Support for Java by Red Hat, in Standard mode | definite |
| Other brace-style languages | The language's own extension, if it implements LSP Call Hierarchy | possible |
Red Hat's Java extension is deliberately not a hard dependency — CatchMe installs and works for other languages without it.
Using it
Trace a real throw
- Put the cursor on a
throwstatement. - Right-click and choose Find Where This Is Caught.
- Results appear in the Exception Flow view in the activity bar, and a Peek opens at the first handler.
The menu item only appears when the cursor is actually on a throw. If you cannot see it, that is why.
Simulate a throw that isn't there
- Put the cursor anywhere — no
throwrequired. - Right-click and choose Simulate Exception From Here….
- Pick a type from the list, or type a fully-qualified name.
Useful for "if this call started throwing IllegalStateException, who would
notice?" without editing any code.
Reading a result
Results group by destination — where the exception can end up — with the call chain that reaches each one nested underneath:
| Marker | Meaning |
|---|---|
| 🔥 | The throw site the chain starts from |
| ↑ | A frame the exception escaped, showing where it was called from |
| ✓ | A handler that catches it |
| ~ | Same, but only possible — see below |
| ⛔ | Nothing catches it; it leaves the program or thread |
| ⋯ | The search stopped at the depth limit — click to expand further |
Clicking a hop jumps to its call site, not its declaration: that is the line where the exception actually leaves for the next frame.
definite vs. possible
Static analysis cannot be exact where there is virtual dispatch, reflection or dynamic typing, so every result says how much it is worth:
definite— proven against a real type hierarchy.possible— approximate, or the language offers no type information.
Two rules follow, and they point in opposite directions on purpose:
- A chain is rated by its weakest hop. One approximate step makes the whole
route
possible, even when the final type match is exact. - A destination is rated by its best route, because reachability asks whether any chain gets there.
A backend without real type information can never report definite — the core
enforces that regardless of what a provider claims.
Chains that converge, and frames you don't care about
Several call chains reaching one handler collapse into a single destination.
Consecutive frames outside your workspace fold into one … N library frames
node. Set catchme.analysis.includeLibraryCode to follow into dependencies.
Commands
| Command | Where |
|---|---|
| CatchMe: Find Where This Is Caught | Editor context menu |
| CatchMe: Simulate Exception From Here… | Editor context menu |
| CatchMe: Re-run Analysis | Exception Flow view toolbar |
| CatchMe: Clear Results | Exception Flow view toolbar |
| CatchMe: Expand Further | Result node |
| CatchMe: Copy Path as Stack Trace | Right-click a result |
| All are available from the Command Palette as well. |
Settings
| Setting | Default | Meaning |
|---|---|---|
catchme.analysis.maxDepth |
8 |
Maximum interprocedural hops when following callers. |
catchme.analysis.precision |
possible |
How much approximation to include in results. |
catchme.analysis.includeLibraryCode |
false |
Follow propagation into dependencies and the standard library. |
catchme.analysis.timeoutMs |
15000 |
Time budget per analysis; partial results are kept when exceeded. |
catchme.view.autoPeek |
true |
Open a Peek at the first handler after an analysis completes. |
catchme.diagnostics.reportUncaught |
false |
Report uncaught results as Information diagnostics in the Problems panel. |
catchme.providerOverrides |
{} |
Force a specific analysis engine per language, overriding automatic selection. Keys are language ids; values are a provider's engine name — e.g. { "java": "Generic (syntactic + LSP Call Hierarchy)" } to bypass jdt.ls. |
Troubleshooting
"Find Where This Is Caught" is not in the menu.
It only shows when the cursor is inside a throw. Use Simulate Exception From
Here… anywhere else.
Java results say the backend is unavailable. CatchMe needs Red Hat's Java extension running in Standard mode — LightWeight mode has no resolved type bindings, and answering without them would produce confidently wrong results, so it refuses instead. Check the status bar and wait for indexing to finish.
Results stop at "depth limit reached".
The search is bounded so a cyclic call graph cannot hang the editor. Click
expand further to continue, or raise catchme.analysis.maxDepth.
A handler you expected is missing. Where several chains converge on the same call site, only the first continues through it — results are representative routes, not every possible route. That bound is what keeps recursive graphs finite.
Everything is possible and nothing is definite.
Expected for any language other than Java: without a type hierarchy, a handler
match cannot be proven. See definite vs. possible.
Something else?
Please open an issue — there are templates for bug reports, feature requests and questions.