Developers · problem and fix
How to read a Java stack trace on Mac: find the real cause, for beginners
A Java stack trace is a list of method calls that were running when an exception was thrown. To read it, start with the exception line, find the first frame that points at your own code, then follow any Caused by lines down to the root. Most people stop at the top line. That line tells you what broke, not always why it broke.
The short answer
- Read the exception class and message first. They name the problem in one line.
- Find the first frame that names your own package. That is the first place to look.
- Follow every Caused by line to the bottom. The last one is usually the root failure.
- Check line numbers against the code that actually ran. A stale build sends you to the wrong line.
- Reproduce the error before you change anything, then change one thing at a time.
45.2%
of 2025 Stack Overflow respondents picked debugging AI-generated code as more time-consuming
Stack Overflow Developer Survey 2025: AI66%
picked AI answers that are almost right, but not quite, in the same survey
Stack Overflow Developer Survey 2025: AI1,717,800
software developer jobs in 2025, according to the Bureau of Labor Statistics
Occupational Outlook Handbook: Software Developers$135,980
May 2025 median annual wage for software developers, per the Bureau of Labor Statistics
Occupational Outlook Handbook: Software DevelopersWhat reading stack traces and error messages costs you
Debugging comes up about every eight minutes
A small observational study followed 11 professional developers across 30 hours of live-streamed programming. It found debugging happened about once every eight minutes. The study counted how often it happened, not how much of the day it took. Reading errors is routine work, so the small delays add up.
Stuck time has a salary cost
The BLS May 2025 median wage for software developers is $135,980. Divided by 2,080 hours, that comes to about $65 an hour. That figure is my math, not a BLS number, and it leaves out benefits and overhead. An hour lost to one confusing trace still costs real money.
AI answers that are almost right
In the 2025 Stack Overflow survey, 66% of respondents picked AI answers that are almost right, but not quite. Another 45.2% said debugging AI-generated code is more time-consuming. A plausible explanation of a trace can send you to the wrong file for a long stretch.
Quick rewrites that do not save time
One study with 106 participants tested GPT-4 rewrites of compiler errors. The rewrites beat conventional messages on time-to-fix in only one of six tasks. Expert written explanations did better. Do not assume a fast AI summary will save you time.
Why it happens
The top line names a symptom
The exception line says what broke, such as a null value or a closed connection. It does not say how the value got that way. Most of the work is tracing back from the symptom to the first bad decision in the flow. Treat the top line as the start of your search, not the answer.
The real failure hides in a Caused by line
Libraries and frameworks often catch an error and throw a new one. The wrapper shows up at the top. The real failure sits under a Caused by line, sometimes several levels down. Readers who stop at the first block miss it.
Most frames belong to other code
A trace from a web app or a test may list many frames before your code appears. Those frames come from the JDK, the framework, and the test runner. They are accurate, but they hide your call site. Scanning for your package takes practice.
Line numbers can point at the wrong version
A line number belongs to the file version that was compiled. If you edited the file after the run, the number points at new code, or at nothing useful. A stale build is an easy reason a trace looks wrong. Rebuild before you trust it.
Most bugs are logic errors, not crashes
In a questionnaire of 102 programmers describing bugs they had fixed, about 69.6% were semantic bugs. Those are wrong results from code that runs without errors. A trace shows where the program stopped, but a logic bug can stop far from its cause. That gap is why the trace alone is not enough.
Finding the bug is harder than fixing it
In the same study of 102 programmers, locating a bug was harder than reproducing or fixing it. A stack trace helps with location, but only if you read it well. Skipping reproduction turns a short search into a long one.
Error messages are written for compilers
Compiler and runtime messages describe the rule that broke. They rarely explain what you meant to do. In one study with 106 participants, GPT-4 rewrites of compiler errors helped time-to-fix in only one of six tasks. Expert explanations did better, so clear wording matters more than extra text.
How to fix it
These work with or without any app.
Read in a fixed order
Start with the exception class and message. Then read the first frame from your code, then the Caused by lines from the bottom. Writing the order on a sticky note helps at first. After a few traces, it becomes a habit you do without thinking.
Treat your first own-code frame as the suspect
Open the file at that line and read the lines above and below it. Look for a variable that could be null, empty, or out of range. Write down what you think it should hold, then check the caller that passed it in.
Rebuild before you trust a line number
Clean the build, rebuild, and run again so the line numbers match the source you are reading. If the trace moves, you had a stale build. This takes little time and saves a long hunt through the wrong file.
Reproduce before you locate
A study of 102 programmers found that locating a bug was harder than reproducing it. So shrink the input first. Run the smallest case that still throws the same exception, then read the trace from that run.
Use the debugger built into your IDE
Set a breakpoint on the suspect line, then run in debug mode. Step over lines and watch the variables change. The same programmer study found that people often relied only on the debugger built into their IDE, so it is a fair place to start.
Search the exact message
Copy the exception class and the first few words of its message. Paste them into Chrome with quotes. Official docs and community answers often explain the exception in plain words. Read the answer, then check that it matches your code.
Ask a teammate with a clean paste
In Slack, wrap the trace in triple backticks so the layout stays intact. Add the one line you expected to see. Remove secrets before you send it, even inside a private channel.
Use an error tracker only for production
If the trace only happens for real users, an error tracker groups repeated errors and keeps the trace. Sentry lists a Developer plan as free, with a limit of 5k errors on its pricing page. Check their pricing page for current limits before you rely on it.
A stack trace is Java's record of where a program was when something went wrong. The JVM prints one when an exception is thrown and nothing in the code catches it. You will see it in Terminal, in the run panel of your editor, in a test report, or in a log file. The format is the same in all of these places. Learn to read it once, and you can read a trace from a web server, a unit test, or a command line tool.

The four parts of a Java stack trace
- The exception line. It holds the exception class, such as java.lang.NullPointerException, then a colon and a message.
- Stack frames. Each line starts with at. It names a class, a method, and the source file with a line number in parentheses.
- Caused by lines. A Caused by line means one exception wrapped another. Each one starts a new block of frames below it.
- More lines. The JVM hides frames that repeat from the enclosing trace and shows a short line that says more, with a count.
Read the frames from the top down. The first frame is where the exception was created. Each frame below it is a call that led to that point. The bottom frame is usually the entry point of the program, such as main.
How to read a Java stack trace, step by step
- Copy the whole trace. Drag across it in Terminal and press ⌘ C, or select it in your editor's run panel.
- Read the exception class and message. A helpful NullPointerException message usually names the variable that was null.
- Find the first frame from your own code. Your package is the reverse domain at the start of your class names, such as com.yourcompany.
- Open that file. In VS Code or Cursor, press ⌘ P, type the file name, then press ⌃ G and type the line number.
- Read the lines around that number. Note which variable could be empty, wrong, or out of range.
- Move to the bottom Caused by line and read the root exception the same way.
- Reproduce the failure with the smallest input you can find, then change one thing at a time.
Write down three things before you touch the code. Record what the message says, which file and line it points at, and which value looked wrong. That note keeps you from chasing guesses.
Find your own code in a long stack trace
Long traces are mostly framework and JDK frames. Frames that start with java., javax., or jdk. belong to Java itself. Library frames carry their own package names. Scan down until you see a package you recognize as yours, then stop there.
Treat that first frame as a suspect, not a verdict. Your code may be correct and still receive a bad value from its caller. Read one frame up to the caller, then ask where the bad value came from. That question usually leads to the real bug.
Modern Java versions usually name the null variable in a NullPointerException message. Older traces only show the line. In both cases, the message tells you what was null, not why it became null. You still have to trace the value back.
How to follow the Caused by chain in Java
A Caused by line means a lower layer failed first. Your code or a library caught that failure and threw a new exception that wraps it. Java prints the original below the wrapper. Start at the bottom Caused by line. The root exception often names the true failure, such as a missing file or a refused connection.
Here is a small example. The top line says an import failed. The Caused by line below says a file was not found, followed by a path. You now know to check the path and the file, not the import code. The wrapper showed where the failure surfaced. The root showed what failed.

Worked example: a null value from a customer lookup
Say the top line reads NullPointerException, and the message says a String is null where length is called. The first frame from your code is Invoice.total. The frame above it is Report.build, which calls total with an invoice from a customer lookup. Open Invoice.total first, and find the field that is null.
Now you have two questions. Why does total assume the name is set? Why did the lookup return a customer with no name? The second question is the real bug. The fix belongs in the lookup or in data validation, not in total. The trace showed where the crash happened. It did not show where the bad data started.
Java stack trace on a Mac: where to search
- Terminal: press ⌘ F to search the output for a class name. You can also find the same bar under Edit > Find > Find.
- Editor: press ⇧ ⌘ F in VS Code or Cursor to search every file for a class or method name.
- Chrome: press ⌘ L to jump to the address bar. Paste the exception class and the first few words of the message in quotes.
- Console: a normal Java exception prints to the output and does not create a crash report. If the whole Java process crashes, open Console and check Reports in the sidebar.
Console sorts reports into user reports and system reports. You can see the user reports for apps you use. Only an administrator can view every report. Crash report files end in .ips, so use the file name and the time stamp to match a report to the run that failed.
Common mistakes when reading stack traces
- Reading only the top line and guessing a fix.
- Editing JDK or framework code, which you usually cannot change, instead of your own call site.
- Trusting a line number from an old build. Clean the project and rebuild first.
- Logging only the message. The message drops the stack and the Caused by chain. Log the whole exception object instead.
- Pasting a trace with tokens, emails, or customer IDs into a chat tool without removing them.
- Accepting an AI explanation without opening the file it names.
Where Lazur helps while you read a trace
Lazur is a voice assistant that lives in the notch on your Mac. Hold ⌥ ⌘ and ask what the trace means. Lazur sees your screen while you hold the shortcut and answers out loud. Ask where the first line from your code is, and Lazur draws a circle and a label around it.
Lazur has limits, and they matter for this job. It does not click through Cursor, run your build, or edit your files. Its guide mode walks you through one step at a time and waits for each click. The reading, the reasoning, and the fix still belong to you. Treat its explanation as a lead to check against the code.
Turn the trace into a clear bug report
Once you know the cause, the report is the next job. Paste the trace into a Linear issue or a Slack message. In Slack, wrap it in triple backticks so the layout holds. Add two lines above it that describe what you expected and what happened. Hold fn to dictate those lines at the cursor in any app. See AI dictation for developers for more.
Privacy and work rules for pasted traces
Traces often contain customer emails, internal hostnames, file paths, and tokens. Remove them before you paste into Slack, Linear, or an AI tool. Lazur listens and looks at the screen only while you hold the shortcut. Audio and the screenshot go to AI providers to answer and are not stored. Content is never used to train AI models.
If you work with client records, patient data, or other regulated information, follow your employer's rules first. Some rules forbid pasting that data into any outside tool. When you are unsure, redact the trace or ask your team before you share it.
Next steps for reading errors faster
Start with one trace from your own project this week. Use the order in this guide, and write the note before you change code. The VS Code guide and the Cursor guide cover the shortcuts used here. For the full list of ways Lazur helps with errors, see Lazur for developers. Trial details are on the pricing page.
Faster with Lazur
Where Lazur helps with reading stack traces and error messages
Hold ⌥ ⌘ and say what you want. Lazur sees your VS Code window. Lazur draws a circle and a label around the button or menu you need.
- 1
Hold ⌥⌘ and talk
- 2
Lazur draws a circle and a label around the button or menu you need.
- 3
You stay in VS Code. Nothing to copy into a chat window.
More things to say in VS Code
- “What does this exception mean?”
- “Where is the first line from my code?”
- “Walk me through opening that file in Cursor.”
- “Find the docs for this exception.”
- “Draft a Slack message with this trace.”
- “Dictate the bug summary into Linear.”
Free for 3 days, then $18/month. Download for Mac
You say“Which line in this trace is my code?”
Lazur · points at itLazur circles the first frame that names your package and labels it on screen.
What developers say to Lazur for this
Each one is a single hold of ⌥ ⌘.
“What does this exception mean?”
Lazur reads the trace on your screen and explains the exception out loud, in plain words.
Explains what's on screen
“Where is the first line from my code?”
Lazur draws a circle and a label around that line, so you find it faster.
Points at it
“Walk me through opening that file in Cursor.”
Lazur gives one step at a time and waits for each click. It does not click for you.
Walks you through it
“Find the docs for this exception.”
Research runs in Lazur's own Chrome tabs and comes back with a summary and a report.
Researches in the background
“Draft a Slack message with this trace.”
Lazur drafts the text and can type it where your cursor is. You review it before anything is sent.
Drafts it
“Dictate the bug summary into Linear.”
Hold fn to dictate clean text at the cursor in any app, so the summary takes less typing.
Types what you say
A plan you can start this week
- Day 1
Read the first line only
Pick one trace from your own project. Write the exception class and the message in one sentence each. Do not open any file yet. This forces you to name the symptom before you guess at the cause.
- Day 2
Find your first own-code frame
Scan the trace for your package. Open that file in VS Code or Cursor with ⌘ P. Read the lines above and below the frame, and note the variable that looked wrong.
- Day 3
Follow the Caused by chain
Go to the bottom Caused by line. Write the root exception in your note. Check whether it names a file, a network call, or a value that came from outside your code.
- Day 4
Reproduce, then check line numbers
Shrink the input until the same exception appears. Clean and rebuild the project. Confirm the line numbers match the file you are reading before you edit anything.
- Day 5
Write the note and share it safely
Remove secrets and customer data from the trace. Paste it into Linear or Slack with two lines about what you expected. Dictate the summary if typing slows you down.
Questions people ask
What does Caused by mean in a Java stack trace?
Caused by means an exception was wrapped inside another exception. The lower layer failed first, and the code above it threw a new error with the original attached. Read the bottom Caused by line first, because it usually names the true failure. Each Caused by block has its own frames, so read those top down too.
Which line should I read first in a Java stack trace?
Read the exception class and message first. Then find the first at line that names your own package. After that, look at the Caused by lines, starting from the bottom. This order gets you to the suspect file fastest in most cases.
Why does my trace show lines from java.base?
Those frames come from the Java standard library, which runs your code. The module name java.base shows where Java itself was when the failure happened. You rarely change that code. Scroll down to a frame from your package and start there.
Why do the line numbers in my trace not match my code?
Most often, the code you are reading is not the code that ran. You may have edited a file without rebuilding, or your IDE compiled a different version than your terminal ran. Clean the build, rebuild, run again, and read the new trace.
Can I read a Java stack trace on a Mac without an IDE?
Yes. Terminal shows the output, and any text editor can open the source files. Press ⌘ F to find a class name in Terminal, and use your editor's search across files to find the code. An IDE can make frames clickable, but the reading method stays the same.
Is it safe to paste a stack trace into an AI tool?
Remove tokens, emails, customer IDs, and internal hostnames first. Follow your employer's rules about outside tools. Lazur only listens and looks at the screen while you hold its shortcut, and screenshots are not stored. Still, redact the trace before you share it anywhere.
What if my program fails without printing a stack trace?
Check the log file or output your program writes. If the whole process crashes instead of throwing an exception, open Console and look under Reports, then Crash Reports. Crash report files end in .ips, so look for that extension.
Sources
- Stack Overflow Developer Survey 2025: AI · Stack Overflow · checked 2026-11-07
- Stack Overflow press release: 2025 Developer Survey · Stack Overflow · checked 2026-11-07
- An Exploratory Study of Debugging Episodes · arXiv · checked 2026-11-07
- Occupational Outlook Handbook: Software Developers · U.S. Bureau of Labor Statistics · checked 2026-11-07
- Not the Silver Bullet: LLM-enhanced Programming Error Messages are Ineffective in Practice · arXiv · checked 2026-11-07
- What we can learn from how programmers debug their code · arXiv · checked 2026-11-07
- View reports in Console on Mac · Apple Support · checked 2026-11-07
- Sentry Pricing · Sentry · checked 2026-11-07
Fix reading stack traces and error messages with Lazur, free for 3 days
Hold a key and ask. Lazur sees your screen, points at the button and talks you through it, in any Mac app. No credit card.