# S02 — The exception hierarchy Guide: ("JacksonException Is Now Unchecked") [`before/S02ExceptionHierarchy.java`](../jackson2-before/src/main/java/com/ankurm/migration/before/S02ExceptionHierarchy.java) · [`after/S02ExceptionHierarchy.java`](../jackson3-after/src/main/java/com/ankurm/migration/after/S02ExceptionHierarchy.java) The guide calls this the most dangerous change and it is right. But the failure mode is narrower than "every `catch (IOException)` silently stops catching", and the difference decides how much of your codebase you actually have to audit. **Case A — the try block contains only Jackson calls.** `catch (IOException)` becomes a *compile error*: "exception java.io.IOException is never thrown in body of corresponding try statement". The compiler finds these for you. No audit needed. **Case B — the try block also does real I/O.** `IOException` is still reachable from the I/O, so the catch block compiles, and it silently stops covering the Jackson call. Nothing warns you. This is the shape that reaches production, and it is what the example runs. ## Output **Jackson 2 — `jackson2-before`** ``` JsonProcessingException extends IOException : true caught by catch (IOException) : JsonParseException writeValueAsString declares : [class com.fasterxml.jackson.core.JsonProcessingException] ``` **Jackson 3 — `jackson3-after`** ``` JacksonException extends RuntimeException : true JacksonException extends IOException : false ESCAPED catch (IOException) : StreamReadException caught by catch (Jackson...) : StreamReadException writeValueAsString declares : [class tools.jackson.core.JacksonException] <- nothing checked ``` So the audit target is narrower and more specific than "grep for `catch (IOException)`": it is `catch (IOException)` blocks that contain **both** I/O and a Jackson call. Those are the ones the compiler cannot help with. Note the last line of each. Jackson 3 still *declares* `JacksonException` on `writeValueAsString`, but since it is unchecked, callers are not forced to handle it — which is what lets Jackson calls sit inside lambdas without a wrapper.