Python Traceback: How to Read Error Messages
A traceback is the report Python prints when an error stops a program. It lists every function call that led to the failing line, oldest first.
This lesson shows how to read a traceback and use it to find the cause of a bug. Read Debugging first.
Read a traceback from the bottom up
This program calls one function from another. The error happens two calls deep.
def average(scores):
return sum(scores) / len(scores)
def report(scores):
print("Average:", average(scores))
report([4, 6])
report([]) # this call raises ZeroDivisionError
The first call prints Average: 5.0. The second stops with a traceback. Read
it from the bottom:
- The last line is the error type and message:
ZeroDivisionError: division by zero. - The frame above it is the line that failed, inside
average. - The frames higher up show who called it:
report, then the top-levelreport([])line.
Find the cause, not just the crash
The line a traceback points at is where Python noticed the error. The bug
is where a value became wrong. These are often different lines. Here
average divides correctly; the problem is the empty list passed in at the top. Work up the frames and ask, at
each one, "was this value already wrong here?"
Here the fix belongs in report, which knows what an empty list should mean:
def average(scores):
return sum(scores) / len(scores)
def report(scores):
if len(scores) == 0:
print("No scores yet")
else:
print("Average:", average(scores))
report([4, 6])
report([])
This prints Average: 5.0, then No scores yet.
Get the traceback as text
The traceback module prints the same report without stopping the program. It
is useful in a log, or to compare two runs.
import traceback
def average(scores):
return sum(scores) / len(scores)
try:
average([])
except ZeroDivisionError:
traceback.print_exc()
print("still running")
The traceback prints, then still running. Choose this only when the program
must keep going and you still want the full report. While you are debugging,
let the error crash the program: an except that prints nothing hides the
traceback you need.
Note: in the browser the traceback may name the file <exec> instead of a
real file name. A program run from a file shows its path and line numbers.
See also: Try and except, Raising exceptions.
Your turn
total_cost crashes. Read the traceback, find the frame where the value
first goes wrong, and fix the cause so the program prints the totals.
def total_cost(prices):
total = 0
for price in prices:
total = total + price
return total
def checkout(items):
prices = []
for item in items:
# read the traceback: which frame first has a wrong value?
prices.append(item[1])
return total_cost(prices)
print(checkout([("pen", "2"), ("book", "15")]))
print(checkout([]))
Expected output
17
0