💥 Exceptions & Errors · Intermediate

Errors you should not catch in Java

OutOfMemoryError, StackOverflowError and why.

🧩 The mysteryYour server runs out of memory. A teammate suggests: "Just catch OutOfMemoryError and carry on!" Java allows it. Why is it a terrible idea?

When the JVM itself is in trouble

Errors signal problems a program usually can't recover from. OutOfMemoryError: the heap is exhausted. StackOverflowError: the thread's stack is full, usually from runaway recursion. Both extend VirtualMachineError → Error — not Exception, so catch (Exception e) won't catch them.

🔮 Predict it

A recursion with no exit

What happens?

int down(int n) {
    return down(n - 1);
}
void main() {
    System.out.println(down(10));
}
  1. Prints 0
  2. Throws StackOverflowError
  3. Runs forever
  4. Throws OutOfMemoryError
Show the answer

Every call adds a stack frame, and nothing stops the recursion. The thread's stack fills up and the JVM throws StackOverflowError — fast, not forever.

Every recursion needs a base case

The fix isn't a catch — it's the code. A recursive method must have a base case that stops it. Without the first line, factorial(5) would crash with StackOverflowError.

int factorial(int n) {
    if (n <= 1) return 1;          // base case
    return n * factorial(n - 1);
}
⚠️ The trap

Catching Errors to carry on

Errors can be caught, but the code that was interrupted may have left objects half-updated, and after an OutOfMemoryError there may be no memory even to handle it. Carrying on risks wrong results. Fix the cause; catch Throwable only at the very top — to log and shut down cleanly.

try {
    handle(request);
} catch (OutOfMemoryError e) {  // bad idea
    // retry? continue? state is unknown
}
🤔 Think first

Days of uptime, then OOM

A server throws OutOfMemoryError after several days of running. What's the better approach than catching it?

Think about it, then reveal the answer

Growth over days points to a memory leak — e.g. an ever-growing cache or static map. Take a heap dump to find what's piling up and fix it, or raise the heap limit with **-Xmx** if the usage is legitimate.

💼 In the real world

Production settings

Ops teams start Java services with -XX:+HeapDumpOnOutOfMemoryError, so a crash leaves a heap dump to analyze. -Xmx sets the maximum heap and -Xss sets the thread stack size — tuning knobs, not substitutes for fixing leaks and broken recursion.

Key takeaways

  1. StackOverflowError: usually recursion without a working base case
  2. OutOfMemoryError: heap exhausted — a leak, or -Xmx too small
  3. Errors are unchecked; catch (Exception e) won't catch them
  4. Fix the cause; catch Throwable only at the very top, to log
🤯 Did you know?

The Q&A site Stack Overflow, launched in 2008, took its name from exactly this kind of error — the stack overflow every programmer meets sooner or later.

Practice questions

What does this print?

int depth(int n) {
    return depth(n + 1);
}
void main() {
    System.out.println(depth(0));
}
  1. Throws StackOverflowError
  2. Throws OutOfMemoryError
  3. Prints 0
  4. Runs forever
Check your answer

Throws StackOverflowError. Every call adds a stack frame and nothing stops the recursion, so the thread's stack fills up.

A server throws OutOfMemoryError after several days of uptime. A teammate suggests catching OutOfMemoryError around each request and carrying on. Better approach?

  1. Find the leak (e.g. an ever-growing cache) from a heap dump, or raise -Xmx if usage is legitimate
  2. Catch Throwable instead to be extra safe
  3. Call System.gc() inside the catch block
  4. Catch it and retry the request in a loop
Check your answer

Find the leak (e.g. an ever-growing cache) from a heap dump, or raise -Xmx if usage is legitimate. Growth over days points to a leak. Catching the error just postpones the crash and may leave data half-updated.

Next: the golden rules — never swallow, fail fast, keep the cause. Small habits that save whole nights of debugging.