When things go wrong
How to read a traceback without panic, the three errors you will meet first, and catching the ones you can answer.
The report at the bottom
When a line cannot run, Python stops there and prints a report called a traceback. It looks alarming and reads simply, as long as you start from the bottom.
The last line names the problem: the kind of error, and a sentence about what it wanted. The line above points at the place — a line number and a copy of the code. Read the last line, then look at the line number it mentions, and ignore the middle until you need it.
Three you will meet first
NameError— a name that does not exist. Nine times out of ten it is text missing its quotes, or a variable spelled differently two lines apart.TypeError— two values that cannot be used together, like text and a number with+. The fix is deciding which one should change.ValueError— the type is right and the value is impossible:int("twenty")is asked to turn words into a number.
Catching what you can handle
Some failures are not bugs, they are news: a visitor typed a word where a number was asked for. try runs the risky lines, and except answers the error you expected — the program continues instead of stopping.
The except line names which error it answers. except ValueError: catches a bad value and lets every other kind of problem through, which is what you want: an error you did not expect is information, not noise to hide.
A bad value, answered
text = "twenty"
try:
age = int(text)
print(f"Age: {age}")
except ValueError:
print("That is not a number.")Catch narrowly, or not at all
A bare except: — with nothing after it — catches everything, including the mistakes you made in your own program. It turns a helpful traceback into silence, and silence is the hardest thing to debug.
Name the error you can answer, and leave the rest to stop the program loudly. The loud version takes a minute to read; the silent version can take an afternoon.
A number that might not be one
Right now the program stops with a ValueError. Wrap the conversion so bad text prints a friendly line instead — then change the text to a real number and run it again.
The middle of the traceback is a path
The frames above the error are the calls that led to it, oldest at the top and newest at the bottom. For a one-line program there is nothing to read. For a program with functions, the frame just above the error names the function that was running, and the one above that names its caller.
That path is the useful part when the failing line looks innocent. A conversion that fails on a value passed in from elsewhere points at the conversion, but the mistake may be in the caller that supplied the value. Read upward until the values stop making sense.
An error message is written for the person debugging
The sentence after the error type is not decoration. invalid literal for int() with base 10: 'twenty' names the function, the base and the exact text it refused. Reading it slowly often saves a print statement, because it already says which value was wrong.
When you write your own handler, keep that habit: say what was expected and what arrived. A message like “bad input” sends the next reader back to the code; “expected a number, got twenty” ends the investigation.
Read the last line first. It names the problem; the line above it points at the place. The middle of the traceback is only interesting when your own functions call each other.
An error travels up until something catches it
When a line fails, Python does not jump to the next line. It stops that function and hands the error to whoever called it, then to their caller, until some try names that kind of error or the program runs out of callers and stops.
That is why the traceback lists several places: the bottom is where the error happened, and the frames above are the calls that led there. It is also why a try only protects the lines inside it — an error raised after the block, or in a different function that does not catch it, keeps travelling.
Naming the error object
except ValueError as error: gives the exception object a name, so the handler can print or re-raise it. The object carries the message Python wrote, which is often more specific than the type alone.
finally runs whether the try succeeded or failed, which is the place for cleanup. else runs only when no error happened. Most programs need only try and except, but the two extra clauses make the intent exact.
Three ways a try makes debugging harder: a bare except: catches your own typos as well as the error you expected; a try wrapped around too much code blames the wrong line; and an except that prints nothing turns a loud failure into silence.
Try these next
- Catch
ZeroDivisionErroraround10 / 0and print a sentence instead. - Put two conversions in one
try, make the second fail, and work out which line the traceback names. - Remove the
exceptand read the traceback from the bottom up before putting it back.
A division that can fail
`divide(10, 0)` would stop the program. Add `try` and `except ZeroDivisionError` inside the function so it returns `None`, then call it with a good and a bad denominator and print a plain sentence for each.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
Which error does int("twenty") raise?
