An error message is not a failure — it is Python telling you exactly what went wrong and where. Most beginners see a wall of red text and panic. Experienced programmers see the same text and immediately know where to look. The difference is not talent — it is knowing how to read what Python is telling you. This article teaches you to do exactly that.
1 Errors Are a Normal Part of Programming
Every programmer — from complete beginner to senior engineer with twenty years of experience — writes code that produces errors. The goal is not to write perfect code on the first attempt. The goal is to read the error, understand it, and fix it efficiently.
When you make a wrong turn, a sat-nav does not give up — it says "recalculating" and gives you a new route. A Python error message is the same thing: it is not telling you that you have failed, it is telling you exactly which turn was wrong so you can find your way back. The sat-nav that says nothing when you go wrong is far more dangerous than the one that speaks up.
There are three broad categories of error in Python. Understanding which category you are dealing with changes how you approach the fix:
| Category | When it happens | What Python does | Example |
|---|---|---|---|
| Syntax Error | Before the program runs. Python cannot parse your code. | Refuses to start. Points to the offending line. | Missing colon after if, unmatched bracket. |
| Runtime Error | While the program is running. | Program crashes at the exact line where it occurred. | Dividing by zero, accessing a missing key. |
| Logic Error | While the program is running — or after. | No crash. Program produces the wrong result silently. | Using > instead of >=, adding when you meant to multiply. |
Syntax and runtime errors are actually the easier bugs — Python tells you about them directly. Logic errors are silent: the program runs without complaint but produces the wrong answer. This article focuses on syntax and runtime errors, because those are the ones Python reports. Logic errors require a different skill — careful tracing — which you practise in the loop and conditional articles.
2 Anatomy of an Error Message
When Python encounters a runtime error, it prints a traceback. A traceback is a report showing the chain of function calls that led to the crash, followed by the error type and a description. Here is a real example:
Traceback (most recent call last):
File "mission.py", line 12, in <module>
result = calculate_fuel(speed, distance)
File "mission.py", line 7, in calculate_fuel
return distance / speed
ZeroDivisionError: division by zeroThis looks intimidating at first. Let's dissect every part:
| Part of the message | What it tells you |
|---|---|
Traceback (most recent call last): | A header. Tells you what follows is a traceback — a chain of calls leading to the crash. You can mostly ignore this line. |
File "mission.py", line 12, in <module> | The filename, the line number, and where in the code it was called from. <module> means it was called from the top level of the file (not inside a function). |
result = calculate_fuel(speed, distance) | The actual line of code that triggered the chain. Python shows you the source line so you can see it directly. |
File "mission.py", line 7, in calculate_fuel | The crash happened inside a function called calculate_fuel, at line 7 of the file. |
return distance / speed | The exact line where Python crashed. |
ZeroDivisionError: | The error type — the category of problem. This is the most important word to read. |
division by zero | The error message — a plain-English description of what went wrong. |
When you see a traceback, read it in this order:
1. Jump to the last line first — the error type and message tell you what went wrong.
2. Read the last file/line reference — this is where the crash happened.
3. Scroll up the traceback only if needed — the upper entries show you how you got there, which matters for bugs inside functions.
3 Where to Find Error Messages in VSCode
In VSCode, when you run a Python file, output and errors both appear in the Terminal panel at the bottom of the screen. If the terminal is not visible, open it with Ctrl + ` (backtick) on Windows/Linux, or Cmd + ` on macOS.
Error messages appear in red text. Normal program output appears in white. A typical session looks like this:
PS C:\Users\student\projects> python mission.py
Traceback (most recent call last):
File "mission.py", line 12, in <module>
result = calculate_fuel(speed, distance)
File "mission.py", line 7, in calculate_fuel
return distance / speed
ZeroDivisionError: division by zero3.1 Clicking the Line Number in VSCode
VSCode makes one part of the traceback interactive: the filename and line number (e.g. mission.py, line 7) appears as a clickable link in the terminal. Clicking it jumps your cursor directly to that line in the editor. This is one of VSCode's most useful features — use it every time.
3.2 The Red Underline in the Editor
For syntax errors, VSCode often catches the problem before you even run the file — a red squiggly underline appears under the offending code. Hovering over it shows a tooltip with the error description. This is the fastest possible feedback loop: fix the syntax before you run, not after.
Before running your program, scan the editor for red underlines. VSCode's Python extension (Pylance) catches most syntax errors and many common mistakes — undefined variable names, wrong indentation, mismatched brackets — as you type. A clean editor with no red underlines does not guarantee the program is correct, but it does mean there are no obvious syntax problems.
4 The Common Error Types
Python has a specific name for every category of runtime error. Learning these names means you can recognise the problem the moment you see the last line of any traceback. Here are the eight you will encounter most often in Grade 9.
4.1 SyntaxError — "I can't read this"
A SyntaxError means Python cannot parse your code at all. The program never starts. Python found something that does not follow the rules of the language — a missing colon, an unclosed bracket, a misplaced keyword.
# Common causes of SyntaxError:
if score > 50 # missing colon
print("pass")
print("hello" # unclosed parenthesis
def calculate(a, b) # missing colon after def
return a + bWhat you see in the terminal:
File "ship.py", line 1
if score > 50
^
SyntaxError: expected ':'The caret symbol ^ points to the position where Python got confused. Note that Python's pointer sometimes sits one character after the actual mistake — look at the character just before the caret too.
Go to the line number shown. Read the line out loud and ask: is the colon there? Are all brackets closed? Is anything misspelled? VSCode's red squiggle will usually be sitting right on the problem before you even run the file.
4.2 IndentationError — "This line is in the wrong place"
Python uses indentation to define structure. An IndentationError means a line's indentation does not match what Python expects — either too many spaces, too few, or a mix of tabs and spaces.
def greet(name):
print("Hello,", name) # should be indented File "ship.py", line 2
print("Hello,", name)
^
IndentationError: expected an indented block after function definition on line 1VSCode inserts 4 spaces when you press Tab, which is correct Python style. If you paste code from somewhere that used actual tab characters, you may get an IndentationError even though the code looks correctly indented. The fix: select all the code, then use Edit → Convert Indentation to Spaces in VSCode. Or simply retype the indentation yourself.
4.3 NameError — "I've never heard of that"
A NameError means Python encountered a name — a variable or function — that has not been defined yet at that point in the program.
print(ship_name) # ship_name was never assigned
Traceback (most recent call last):
File "ship.py", line 1, in <module>
print(ship_name)
^^^^^^^^^
NameError: name 'ship_name' is not definedCommon causes:
- Typo in the variable name:
shiip_namevsship_name. - Using a variable before assigning it.
- Using a local variable outside the function it was created in (scope — see Article 6).
- Calling a function before defining it.
- Forgetting to import a module:
math.sqrt(4)withoutimport math.
4.4 TypeError — "You can't do that with those types"
A TypeError means you tried to perform an operation on a value of the wrong type — adding a string to an integer, calling something that is not a function, or passing the wrong number of arguments.
age = input("Enter your age: ")
next_year = age + 1 # age is a string — can't add int to strTraceback (most recent call last):
File "ship.py", line 2, in <module>
next_year = age + 1
~~~^~~
TypeError: can only concatenate str (not "int") to strCommon causes:
- Forgetting to convert
input()withint()orfloat(). - Using
+to concatenate a string and a number without converting. - Calling a non-function:
result = 42(). - Passing the wrong number of arguments to a function.
The error message usually tells you exactly which types are involved — read it carefully:
# "can only concatenate str (not 'int') to str" # Translation: the left side is a string, the right side is an int — fix the types first.
4.5 ValueError — "The type is right, but the value doesn't make sense"
A ValueError means the type of your data is correct, but the actual content is not valid for the operation you are trying to perform.
age = int("hello") # the type is str — that's fine for int()
# but "hello" cannot be converted to an integerTraceback (most recent call last):
File "ship.py", line 1, in <module>
age = int("hello")
^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'hello'Common causes:
- Calling
int()orfloat()on a string that is not a number. - Calling
.remove()on a list when the item is not present. - Calling
.index()on a list or string when the item is not present.
4.6 IndexError — "That position doesn't exist"
An IndexError means you tried to access a list or string at an index that is out of range — past the end (or before the beginning with a negative index that is too large).
crew = ["Alice", "Bob", "Carol"] print(crew[5]) # only indices 0, 1, 2 exist
Traceback (most recent call last):
File "ship.py", line 2, in <module>
print(crew[5])
~~~~^^^
IndexError: list index out of rangeCommon causes:
- Using a hardcoded index that is too large for the actual list.
- Off-by-one error — using
range(len(list))correctly but then accidentally accessinglist[len(list)]. - An empty list: trying to access
my_list[0]when the list is[]. - A loop that runs one iteration too many.
4.7 KeyError — "That key doesn't exist in this dictionary"
A KeyError is the dictionary equivalent of an IndexError. You tried to access a key that is not in the dictionary.
ship = {"name": "Persephone", "fuel": 87.5}
print(ship["shields"]) # "shields" key does not existTraceback (most recent call last):
File "ship.py", line 2, in <module>
print(ship["shields"])
~~~~^^^^^^^^^^^
KeyError: 'shields'Common causes:
- Typo in the key name:
"sheild"instead of"shield". - Assuming a key exists when it was never added.
- Case mismatch:
"Name"vs"name".
The fix: use in to check before accessing, or use .get() (see Article 9).
4.8 ZeroDivisionError — "You can't divide by zero"
Python raises this when the right-hand side of a division or modulo operation is zero. This is mathematically undefined, so Python refuses to proceed.
speed = 0 time = 100 / speed # division by zero
Traceback (most recent call last):
File "ship.py", line 2, in <module>
time = 100 / speed
~~~~^~~~~~~
ZeroDivisionError: division by zeroCommon causes:
- A variable that should hold a non-zero number but was initialised to 0 and never updated.
- User input that is 0 when the program did not guard against it.
- Calculating an average on an empty list:
sum(items) / len(items)whenitemsis[].
Match each error to its most likely cause:
Error Likely cause NameError: name 'scroe' is not definedA. Forgetting to convert input()TypeError: can only concatenate str (not "int") to strB. Accessing a position past the end of a list IndexError: list index out of rangeC. Typo in a variable name KeyError: 'altitude'D. Accessing a key that was never added SyntaxError: expected ':'E. Missing colon after ifordefFor each error below, identify the type and explain in one sentence what is wrong:
# Program 1 name = input("Name: ") greeting = "Hello, " + name + " you are " + age + " years old." # Program 2 planets = ["Mercury", "Venus", "Earth"] print(planets[3]) # Program 3 def launch(): print("Liftoff!")A student gets this error. Without seeing their code, what two things do you know for certain?
ZeroDivisionError: division by zero
5 Reading a Traceback Step by Step
Let's practise the three-step reading strategy on a realistic traceback. Here is a program and its error output:
5.1 The Program
# fleet_report.py
def get_average_fuel(fleet):
total = 0
for ship in fleet:
total += ship["feul"] # typo: "feul" instead of "fuel"
return total / len(fleet)
fleet = [
{"name": "Persephone", "fuel": 87.5},
{"name": "Icarus IV", "fuel": 43.0},
]
average = get_average_fuel(fleet)
print("Average fuel:", average)5.2 The Error Output
Traceback (most recent call last):
File "fleet_report.py", line 14, in <module>
average = get_average_fuel(fleet)
File "fleet_report.py", line 5, in get_average_fuel
total += ship["feul"]
~~~~^^^^^^^^
KeyError: 'feul'5.3 Applying the Three Steps
| Step | What you read | What it tells you |
|---|---|---|
| 1. Last line | KeyError: 'feul' | The program crashed because it tried to access a dictionary key called 'feul' — which does not exist. |
| 2. Last file/line | File "fleet_report.py", line 5, in get_average_fuel | The crash happened on line 5, inside the function get_average_fuel. |
| 3. The source line | total += ship["feul"] | There is a typo: "feul" should be "fuel". The key does not exist in the dictionary because it was spelled wrong. |
The fix: change ship["feul"] to ship["fuel"] on line 5.
The traceback shows two entries: the crash happened on line 5 (inside the function), but the call that triggered it was on line 14 (in the main program). If fixing line 5 does not make sense on its own, look at line 14 to understand how the function was called and with what data. Reading the full chain matters most when the bug is in the data being passed in rather than in the function itself.
6 A Quick-Reference Catalogue of Error Messages
Here are the most common error messages you will see in Grade 9, with plain-English translations and the most likely fix for each.
| Error message | Plain English | Most likely fix |
|---|---|---|
SyntaxError: expected ':' | You are missing a colon at the end of an if, elif, else, for, while, or def line. | Add the : at the end of that line. |
SyntaxError: invalid syntax | Python hit something it could not parse. Often a typo, missing bracket, or incorrect keyword. | Check the flagged line and the line above it for missing punctuation. |
IndentationError: expected an indented block | The line after a def, if, for, etc. is not indented. | Indent the body of the block by 4 spaces. |
IndentationError: unexpected indent | A line is indented when it should not be. | Remove the extra indentation from that line. |
NameError: name 'x' is not defined | Python has never seen the name x. | Check for a typo in the name; make sure the variable is assigned before use. |
TypeError: can only concatenate str (not "int") to str | You tried to join a string and an integer with +. | Wrap the integer in str(), or convert the string with int(). |
TypeError: 'int' object is not callable | You put parentheses after a variable that holds a number, treating it like a function. | Check for a variable with the same name as a function, e.g. len = 5 then len(items). |
TypeError: missing N required positional argument(s) | You called a function but did not pass enough arguments. | Check the function definition and make sure you pass all required arguments. |
ValueError: invalid literal for int() with base 10: 'x' | You tried to convert a string to an integer but the string is not a number. | Check what the user actually typed; validate input before converting. |
IndexError: list index out of range | You accessed a list at a position that does not exist. | Check your index value against len(list) - 1; look for off-by-one errors. |
KeyError: 'x' | You tried to access a dictionary with a key that is not there. | Check the key spelling; use in or .get() to access safely. |
ZeroDivisionError: division by zero | The denominator in a division was zero. | Guard with if denominator != 0: before dividing. |
AttributeError: 'NoneType' object has no attribute 'x' | You called a method on None — a variable that holds nothing. | A function returned None when you expected a real value. Check for a missing return statement. |
Python sometimes reports the error at the line after the real mistake — especially for syntax errors. If the flagged line looks correct, look at the line immediately above it. For example, an unclosed parenthesis on line 13 might only cause a SyntaxError to be reported on line 14 when Python encounters the next statement and realises something is wrong.
Similarly, with runtime errors inside functions, the traceback may point to a line that is syntactically fine — the real cause is often in the data that was passed to the function, which you find by reading higher up the traceback.
7 A Debugging Workflow
Having a consistent process for fixing bugs makes the whole experience less stressful. Here is a workflow that works for beginners and professionals alike:
| Step | What to do | Why |
|---|---|---|
| 1. Read the last line | What type of error is it? What does the message say in plain English? | Identifies the category of problem before you look at any code. |
| 2. Find the line | Note the filename and line number. Click the link in VSCode's terminal to jump there. | Takes you directly to the crash site. |
| 3. Read the source line | Read the exact line Python shows you. Can you see the problem? | Often the bug is obvious once you are looking at the right place. |
| 4. Check one line above | Look at the line immediately before the flagged one. | Syntax errors and missing colons often only show up on the following line. |
| 5. Describe the bug in one sentence | Before touching the keyboard, say aloud or write down what you think is wrong. | Forces you to understand the problem before you attempt to fix it. Prevents random editing. |
| 6. Make one change | Fix the specific thing you identified. Do not change multiple things at once. | If you change three things and the error disappears, you will not know which one fixed it. |
| 7. Run again | Run the program. Did the error go away? Did a new one appear? | A new error after fixing the first is progress — not a step backwards. |
The single most important habit in debugging is step 5: describe the bug out loud before you touch anything. Students who skip this step tend to randomly delete lines, change variable names, and rewrite working code — making things worse. Students who describe the bug first almost always fix it in one targeted edit. Your teacher will ask you to do this during desk checks. Practise it now.
8 Worked Examples — Read, Diagnose, Fix
Here are four complete worked examples. For each one: read the code, read the error, apply the three-step strategy, and find the fix before reading the explanation.
Example 1
# Code crew_count = 12 message = "Crew aboard: " + crew_count print(message)
# Error TypeError: can only concatenate str (not "int") to str
Diagnosis: crew_count is an integer. The + operator cannot concatenate a string and an integer.
Fix: message = "Crew aboard: " + str(crew_count)
Example 2
# Code
planets = ["Mercury", "Venus", "Earth", "Mars"]
for i in range(1, 5):
print(planets[i])# Error IndexError: list index out of range
Diagnosis: The list has 4 items at indices 0–3. The loop runs i = 1, 2, 3, 4. When i = 4, planets[4] does not exist.
Fix: Change range(1, 5) to range(1, 4) — or better, use range(len(planets)), or simply for planet in planets.
Example 3
# Code
def warp_speed(distance, time)
return distance / time
print(warp_speed(100, 5))# Error
File "ship.py", line 2
def warp_speed(distance, time)
^
SyntaxError: expected ':'Diagnosis: The def line is missing its colon.
Fix: def warp_speed(distance, time):
Example 4
# Code
def calculate_average(scores):
total = sum(scores)
average = total / len(scores)
return average
result = calculate_average([])
print("Average:", result)# Error ZeroDivisionError: division by zero
Diagnosis: An empty list was passed in. len([]) is 0, causing division by zero.
Fix: Guard against an empty list before dividing:
def calculate_average(scores):
if len(scores) == 0:
return 0
return sum(scores) / len(scores)9 Final Check: The Big Picture
An error message is information, not judgment. Every traceback has three key parts: the error type (last line), the crash location (filename and line number), and the source line (the code Python shows you). Read last-line first, find the line second, check one line above third. Describe the bug in one sentence before touching the keyboard. Errors are not obstacles — they are the fastest feedback you will ever get on what your program is actually doing.
- What are the three steps in the traceback reading strategy? Write them from memory.
Read this traceback and answer the questions below:
Traceback (most recent call last): File "mission.py", line 18, in <module> report = build_report(ship_data) File "mission.py", line 9, in build_report fuel_pct = ship["fuel_level"] * 100 ~~~~^^^^^^^^^^^^^^^ KeyError: 'fuel_level'- What type of error occurred?
- In which file and on which line did the crash happen?
- What is the name of the function the crash happened inside?
- In one sentence, describe the bug.
- What are two possible causes of this specific
KeyError?
Below are four buggy programs. For each one: name the error type you expect to see, explain why the error will occur, and write the one-line fix.
# Program A scores = [90, 85, 78] print(scores[3]) # Program B temperature = input("Enter temperature: ") if temperature > 100: print("Too hot!") # Program C ship = {"name": "Argo", "crew": 50} print(ship["fuel"]) # Program D for i in range(5) print(i)- A student gets a
NameError: name 'total' is not definedon the last line of their program. They are certain they created atotalvariable. Give two possible explanations for why Python still cannot find it. - Explain why "describe the bug in one sentence before fixing it" is useful advice, rather than just immediately trying to fix the code.
10 Quick-Reference: Error Types at a Glance
| Error Type | One-line meaning | First thing to check |
|---|---|---|
SyntaxError | Python cannot parse the code — it won't even start. | Missing colon, unclosed bracket, typo in a keyword. |
IndentationError | A line is indented wrongly — too much, too little, or mixed tabs/spaces. | Check indentation of the flagged line and the block it belongs to. |
NameError | Python has never heard of this variable or function name. | Typo in the name; variable not yet assigned; out-of-scope local. |
TypeError | The operation does not work with the types you gave it. | Mixing strings and numbers; wrong number of arguments; calling a non-function. |
ValueError | The type is right, but the value itself is not valid for this operation. | int("hello"); .remove() on absent item; .index() on absent item. |
IndexError | You accessed a position in a list or string that does not exist. | Check index vs len() - 1; look for off-by-one; check for empty list. |
KeyError | You accessed a dictionary key that is not there. | Typo in key name; key never added; case mismatch. Use .get() or in. |
ZeroDivisionError | You divided by zero. | Guard with if denominator != 0; check for empty list before averaging. |
AttributeError | You called a method on None or the wrong type. | A function returned None — check for a missing return statement. |