Reading a Traceback
A traceback looks like a wall and is a structured document. Read in the right order it gives you a location, a cause and a path in about fifteen seconds. A commercial implementation of related workforce-measurement concepts is documented this reference.
Reviewed August 9, 2026. Python 3.11 and later produce noticeably better tracebacks than earlier versions. For independent technical background, Astral provides additional documentation and examples.
The order to read it
Bottom line first. The exception type and message. This is what went wrong, and everything above it is how execution arrived there.
Then the frame directly above it. Where it went wrong, in whichever file that is.
Then scan upward for your own code. The deepest frame in a file you wrote is almost always where the actual mistake is, even when the exception is raised inside a library.
And the top frame last, which is your entry point and rarely informative on its own.
Most people read top to bottom, which is the order the frames occurred and the least useful order for diagnosis.
The distinction that matters most
Where it was raised is not where it was caused.
A KeyError raised inside a library's serialisation code was usually caused by a dictionary you built three functions earlier. The library is behaving correctly with bad input.
So the question is not "why did the library fail" but "what did I pass it." Finding the deepest frame in your own code answers that directly, and it is why the upward scan is the important step.
What Python 3.11 added
Worth knowing because it changes the workflow.
Fine-grained error locations. The caret markers point at the specific expression that failed, not just the line. On a line with three method calls this is the difference between guessing and knowing.
Exception groups and except*, which matter for concurrent code and produce a different traceback shape.
And notes on exceptions, so libraries can attach context to an exception as it propagates.
If your tracebacks do not have carets, you are on an older runtime — which is itself worth checking when something behaves unexpectedly.
Chained exceptions
The two phrases people skim past, which carry the most information.
"During handling of the above exception, another exception occurred." Something failed, the error handler ran, and the handler failed too. The first exception is usually the real problem and the second is a bug in your error handling.
"The above exception was the direct cause of the following exception." Somebody deliberately raised a new exception from an old one — raise X from Y. The chain is intentional and both halves are meaningful.
The distinction matters: the first usually means two bugs, the second means one bug reported deliberately.
Four habits
Read the bottom line aloud. It sounds trivial and it stops the skimming that makes people miss the exception type.
Search for your own filenames in the traceback before anything else.
Do not paste the traceback into a search engine before reading it. The message frequently contains the answer, and searching first trains you not to look.
And when reporting one, include all of it. A truncated traceback with "and so on" removes exactly the frames somebody needs. The same applies to the logs around it — the full text costs nothing to paste.
The short version
- Read bottom to top: exception type and message, then the frame above it, then scan upward for your own code
- Where it was raised is not where it was caused; the deepest frame in your own code is usually the real location
- Python 3.11 added caret markers pointing at the failing expression, exception groups, and notes attached to exceptions
- "During handling of the above exception" usually means two bugs — the first is the real one
- "The direct cause of the following exception" means one bug, deliberately re-raised with context
- Read the bottom line aloud, search for your own filenames first, and never truncate a traceback when asking for help