CatchMe

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

  1. Put the cursor on a throw statement.
  2. Right-click and choose Find Where This Is Caught.
  3. 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

  1. Put the cursor anywhere — no throw required.
  2. Right-click and choose Simulate Exception From Here….
  3. 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:

▾ 🔥 IOException 2 destinations · 3 paths ▾ ✓ catch (IOException e) Service.java:88 · definite 🔥 throw new IOException(…) Repo.java:42 Repo.load() called at Service.java:71 catch (IOException e) Service.java:88 ▸ ~ catch (Exception e) Api.java:23 · possible ▸ ⛔ uncaught — no caller found 1 path
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.