Kiru Lab / Foundations: Python as an Instrument / Getting Set Up
Reading Error Messages
You will see thousands of these. Learning to read one properly is worth more than any syntax you memorize.
Hands-On Lab · about 40 minutes
Beginners see an error and feel that something has gone wrong with them. Experienced engineers see an error and feel relief, because the alternative — code that runs and quietly produces the wrong answer — is far worse. An error is the interpreter telling you exactly where it stopped and why. Learn to read it and most problems solve themselves.
Anatomy of a traceback
Traceback (most recent call last):
File "analysis.py", line 12, in <module>
result = average(scores) <- the line that called the failing code
File "analysis.py", line 7, in average
return total / len(values) <- the line that actually failed
ZeroDivisionError: division by zero <- what went wrong- Read the bottom line first. It names the error type and gives a one-line description. That is usually enough.
- Read the second-to-last file/line pair. That is where the failure happened.
- Read upward only if you need to know how you got there. The frames above are the chain of calls that led to the failure.
- Ignore frames pointing into library code you did not write, until you have ruled out your own.
The five errors you will meet first
- SyntaxError — Python could not even parse the file. Usually a missing colon, bracket, or quote, and often on the line *before* the one reported.
- IndentationError — your spacing is inconsistent. Pick four spaces and never mix tabs with spaces.
- NameError — you used a name that does not exist. Usually a typo, or you used it before assigning it.
- TypeError — you did something to a value that its type does not support, like adding a number to a string.
- IndexError / KeyError — you asked for position or key that is not there. Remember lists start at index 0.
print("unclosed # SyntaxError
def f():
return 1 # IndentationError
print(undefined_name) # NameError
print("age: " + 30) # TypeError: can only concatenate str to str
print([1, 2, 3][5]) # IndexError: list index out of rangeWhen there is no error but the answer is wrong
This is the harder case, and the tool is the same one professionals use: print the values. Put a `print()` on either side of the line you suspect and look at what is actually there rather than what you assume is there. The gap between those two is where every bug lives.
def average(values):
print("got:", values, "type:", type(values)) # what did I actually receive?
total = sum(values)
print("total:", total, "count:", len(values)) # are both what I expect?
return total / len(values)In track seven you will debug a language model by hooking its internals and printing activation shapes. It is the same move you are learning right now: stop assuming, look at the actual value. The scale changes; the instinct does not.
Hold on to
- An error is information, not judgment — read the bottom line first
- Five error types cover almost everything you will hit early
- When there is no error, print the values and compare against your assumption
Work through
Try each one before opening the solution. Getting it wrong first is most of where the learning happens.
-
Deliberately produce all five error types from the lesson. For each, write down the bottom line of the traceback and the fix in your own words.
Hint
Copy each snippet from the lesson into its own file and run it one at a time.
Solution
SyntaxError: unterminated string — add the closing quote. IndentationError: expected an indented block — indent the body four spaces. NameError: name is not defined — assign it first, or fix the typo. TypeError: can only concatenate str — convert with `str(30)` or use an f-string. IndexError: list index out of range — the list has 3 items, so valid indices are 0, 1, 2.
print("closed now") # SyntaxError fixed def f(): return 1 # IndentationError fixed defined_name = 1 print(defined_name) # NameError fixed print("age: " + str(30)) # TypeError fixed print(f"age: {30}") # or better print([1, 2, 3][2]) # IndexError fixed -
Write a function that divides two numbers, call it with a zero denominator, and read the traceback. Identify which line failed and which line called it.
Hint
The traceback lists frames oldest first — the failing line is the last file/line pair.
Solution
The bottom frame points at `return a / b`, which is where the division happened. The frame above it points at your call site. The bottom line names the type: ZeroDivisionError. Fixing it means deciding what division by zero should mean for your program — raise a clearer error, or return a defined value — which is a design choice, not a syntax fix.
def divide(a, b): if b == 0: raise ValueError("denominator must be non-zero") return a / b divide(1, 0) # now fails with a message that says what you did wrongCheck your work
Paste this after your own code. If it runs without raising, you have it.
try: divide(1, 0) except ValueError as exc: assert "non-zero" in str(exc) else: raise AssertionError("expected a ValueError") assert divide(6, 3) == 2 print("ok") -
Take a function that returns a wrong answer (write one on purpose — say, a sum that forgets the last element), and find the bug using only print statements. Note how many prints it took.
Hint
Print the inputs at the top of the function and the result just before returning.
Solution
The classic off-by-one: `range(len(values) - 1)` stops one element early. Two prints find it — one showing the input has 5 items, one showing the loop ran 4 times. Most bugs need two or three prints, not a debugger. The number of prints it took you is a useful thing to notice, because it drops fast with practice.
def broken_sum(values): total = 0 for i in range(len(values) - 1): # bug: misses the last element total += values[i] return total def fixed_sum(values): total = 0 for value in values: # iterate the items, not the indices total += value return totalCheck your work
Paste this after your own code. If it runs without raising, you have it.
assert fixed_sum([1, 2, 3, 4, 5]) == 15 assert fixed_sum([]) == 0 print("ok")
Sign in to track your progress through the lab.