On an internal tool at a previous job, I spent a frustrating hour chasing a NullPointerException that turned out to be a red herring — the actual root cause was three "Caused by" sections further down the same stack trace, in an exception I hadn't scrolled far enough to see.

A Java stack trace can actually be several exceptions stacked together, not just one. When code catches an exception and wraps it in a new one before rethrowing — common practice, since a low-level exception like a raw SQL error often needs translating into something the calling code can meaningfully handle — Java prints the new, outer exception first, followed by a "Caused by:" section showing the original exception that triggered it. That chain can nest several layers deep if code wraps exceptions more than once on the way up.

The outer exception — the one printed first, without the "Caused by" prefix — is frequently the least useful part of the trace for finding the actual bug, since it's often a generic wrapper type describing what kind of operation failed, not why. The real root cause is usually in the innermost "Caused by" block, at the very bottom of the trace, which is the opposite of where your eye naturally lands first when scanning top to bottom.

Each exception in the chain still has its own set of stack frames listed underneath it, and Java elides frames the outer and inner exceptions share in common, printing "... N more" instead of repeating them — worth knowing so that line doesn't get mistaken for the trace being cut off or the tool malfunctioning.

The practical habit worth building: when a Java stack trace looks long, scroll all the way to the bottom "Caused by" block before analyzing anything, rather than starting the investigation at the first exception the trace prints. The top of the trace tells you what broke from the caller's perspective; the bottom tells you why.