Reference · module 14
When things go wrong
Everything this module explains, on one page.
try and except
Carry on after an error instead of stopping.
- try: runs the risky lines, and except: runs instead if one of them raises. Without it an error ends the program at that line — with it, the program decides what happens next.
- Everything inside try is covered, and once something raises the REST OF THE TRY IS SKIPPED — it jumps straight to except. So keep the block short: lines you did not mean to guard are lines silently skipped.
- Neither branch is unusual. A file that is missing, a number a person typed wrong, a network that is down — these are ordinary Tuesdays, and try is how a program says what to do about them.
The mistake you are about to make
the whole program inside one try
only the risky line inside the try
Wrapping everything feels safer. On the first failure the rest of the try is skipped — including lines that were never going to fail — and you learn nothing.
Catching one thing
Name the error you expected, and let the others through.
- except ValueError: catches only that one. A bare except: catches everything — including the typo you just made, the interrupt you pressed, and the bug you would rather have seen.
- So name what you expect. int("abc") raises ValueError, a missing key raises KeyError, a missing file raises FileNotFoundError. Catch that one and let anything else stop the program, because anything else is news.
- except ValueError as e: also gives you the error itself, and print(e) shows what it says. Worth doing whenever the message is something a person will read.
The mistake you are about to make
except:
except ValueError:
A bare except looks like caution. It catches everything, including your own typo and the Ctrl+C you just pressed, and turns a failure into silence.
Raising your own
Stop early when the input makes no sense.
- raise ValueError("age cannot be negative") stops the function and hands the problem to whoever called it. You are not reporting a crash — you are refusing to continue with input that makes no sense.
- Do it at the top of the function, before anything else runs. A function that checks halfway through has already done half the work, and half-done work is the hardest kind to undo.
- The message is for the person who has to fix it, usually you in three months. "Invalid input" says nothing; "age cannot be negative, got -5" says what was wrong and what arrived.
The mistake you are about to make
print("age cannot be negative")
raise ValueError("age cannot be negative")
Printing the message feels like enough — somebody will read it. The function meanwhile carries on with nonsense data. Raise actually stops.
else and finally
Say what runs only on success, and what runs no matter what.
- A try can have an else: it runs only when nothing raised. It is how you keep the risky line alone inside try while the work that depends on it sits outside the guard.
- And a finally: which runs either way — after the try, after the except, even after a return. It is for tidying up: closing what you opened, whatever happened to it.
- Together they let the try block hold one line. That is the goal: a guard around exactly the thing that might fail, and nothing else caught up in it by accident.
The mistake you are about to make
closing the file on the last line of the try
closing it in a finally
The last line of the try looks like a safe place for cleanup. If something fails above it, it never runs: whatever must always happen belongs in finally.
Reading a traceback
Find the line that actually broke.
- A traceback is read from the BOTTOM. The last line names the error and says what was wrong; the line above it is where it happened. Everything above that is how the program got there.
- That middle part is the call stack, newest call last. It answers the question the error line cannot: not what broke, but who asked for it — which is usually where the real mistake is.
- When the traceback is not enough, print the value just before the failing line. Not clever, and faster than reading the function again — the value is usually not what you assumed.
The mistake you are about to make
rereading the function and imagining the values
printing the value just before the failing line
The instinct is to reread the code and picture what is in the variables. The value is almost never what you pictured, and one print settles it.