Reading the Traceback
Debugging is a repeatable method: read the traceback, locate the failing line, form a single hypothesis, and test it. · 11 min
Programs stop with errors. Every programmer's, every day — this is normal, not a sign you are doing it wrong. When Python stops, it does not leave you guessing: it prints a traceback, a short report of what went wrong and where. The skill that separates a stuck hour from a two-minute fix is not writing code that never breaks. It is reading that report calmly and following a fixed method: read the traceback, find the failing line, form one hypothesis, and test it. This folio is that method, made routine.
Guess before you learn
A program stops and prints this:
``
Traceback (most recent call last):
File "shop.py", line 3, in <module>
print(totl)
NameError: name 'totl' is not defined
``
Which line should you read first?
Read the last line first. A traceback is written so its final line names the error — the type (NameError) and a plain message ('name totl is not defined'). The lines above trace how the program got there; useful, but secondary. If you reached for the top, keep that pencil mark: reading bottom-up is the single habit that makes tracebacks readable, and it is exactly what the next section drills.
9–12
3–5
When Python stops with an error, it prints a traceback — a short report. Read the last line first: it names the kind of error and says what went wrong in plain words. The line just above shows where it happened. Then make one guess about the cause and change one thing to test whether your guess was right.
6–8
A traceback is the report Python prints when a program stops with an error. Read it from the bottom up. The last line is the most useful: it gives the error type — such as NameError or TypeError — and a message describing the problem. The line above points to the file and line number where it happened, and shows that line of code. From there the method is fixed: locate that line, form a single hypothesis about the cause, make one change to test it, and run again. One idea, one change — so you always know what fixed it.
9–12
A traceback records the chain of calls that led to an error, printed so the triggering error sits on the last line: its type and message. Reading bottom-up gets you the diagnosis fastest, then the line reference above it gives the exact location. Debugging from there is a disciplined loop, not luck. Locate the failing line. Form one hypothesis about the cause — a name misspelled, an index past the end, a string where a number was needed. Make the single change that hypothesis predicts, and run again. If the error is gone, you were right; if not, you have ruled that idea out cleanly. Changing one thing at a time is what keeps the result interpretable.
K–2
When a program breaks, the computer leaves a note called an error. Read the very last line first — it says what went wrong. Then find the line it points to, make one good guess, and try one fix.
Undergrad
A traceback is the exception's stack unwound into text: frames from outermost call to the raising site, terminated by the exception type and message — which is why the last line is diagnostic and you read upward only as far as you must. Effective debugging is the scientific method under a tight loop: observe the failure, localize it to a line, state a falsifiable hypothesis, and run the minimal experiment that discriminates it. The cardinal rule is to vary one thing per run; simultaneous edits confound cause and effect and destroy the signal a clean experiment would give. A reproducible failing case is the precondition for the whole loop.
Postgrad
Treat the traceback as a serialized view of the activation-record stack at the raise point, with the exception type and payload as the terminal, most-specific datum — hence bottom-up reading. Debugging is hypothesis-driven differential diagnosis: from the observed fault, generate candidate causes, order them by prior likelihood given the error class, and design single-variable experiments whose outcomes partition the hypothesis space. Controlling one variable per trial preserves the causal inference; a minimal, deterministic reproduction bounds the search and defeats heisenbugs. The invariants you asserted while writing the code become the oracles you check against while repairing it — debugging and specification are the same activity read in opposite directions.
traceback
The report Python prints when a program stops with an error. Its last line names the error type and message; read it first.
So the reading is bottom-up. The last line has two parts: an error type, one of a small family of names, and a message in plain English. NameError: name 'totl' is not defined tells you a name was used that Python never bound — almost always a typo or a variable used before it was set. The line above, File "shop.py", line 3, is the address: open that file, go to line 3, and you are standing on the failing line. Diagnosis, then location. From there, one hypothesis and one change.
Read the traceback above and plan the fix — the steps fade as you master them
NameError
totl
line 3
total
The error type is a strong hint by itself, because each type comes from a small set of causes. A TypeError means an operation met the wrong kind of value — adding a string to a number, say. An IndexError means you reached past the end of a list or string. A ValueError means the type was right but the value was not allowed, like int('hi'). A ZeroDivisionError means a division by zero. Learn these on sight and the last line often names the fix before you have even found the line.
Why is this true?
Why change only one thing before running again, instead of fixing several suspects at once?
Because if you change three things and the error clears, you do not know which change fixed it — and one of the others may have added a new bug you cannot see yet. One change per run keeps a clean link between what you did and what happened, so every run teaches you something definite.
That is debugging as a method rather than a mood: read the traceback bottom-up for the error type and message, go to the line it names, form one hypothesis, change one thing, and run again. Each error type narrows the causes; each single change keeps the result honest. You now have the whole first arc of programming — statements in order, values and types, decisions and loops, functions, collections, the everyday scans, and a reliable way back when something breaks. Every larger program you write is these same parts, combined with more nerve and read with the same calm eye.
Practice — new ink and old, interleaved
1.What happens when this runs?
``
s = 'cat'
s[0] = 'b'
``
2.What does this print?
``
nums = [5, 1, 8, 3]
best = nums[0]
for x in nums:
if x > best:
best = x
print(best)
``
3.What does this print?
``
a = 2
a = a + 3
print(a)
``
4.What number does print(6 + 6) show?
5.For word = 'CODE', what is the largest index you can use before an IndexError?
6.For s = 'HELLO', what is s[1:3]?
7.A traceback ends with TypeError: can only concatenate str (not "int") to str. What kind of mistake is this?
8.Why does if x = 5: raise an error where if x == 5: does not?
9.For s = 'ARCHIVE', what is s[0:4]?
10.What is nums after this runs?
``
nums = [1, 2, 3]
nums.append(4)
``