RizTech Academy logo
RizTech Academy
Errors and DebuggingLesson 2 of 525 min

The errors every beginner hits, and what they mean

You can now read a traceback. This lesson is the reference for what each error type usually means in practice — not the textbook definition, but the two or three things that actually cause it.

Most of these you have already met somewhere in this course. Having them in one place is the point.

SyntaxError

SyntaxError: expected ':'

Python could not parse your file. Nothing ran at all — this is caught before execution starts, which distinguishes it from everything else here.

Usual causes:

  • A missing colon after if, for, while or def
  • An unclosed bracket, quote or brace
  • = where you meant ==
  • Python 2 code (print "hello")

The reported line is often one after the real problem. If the line looks perfect, check the line above — an unclosed bracket on line 9 is only noticed on line 10.

values = [1, 2, 3
print("hello")

Python reports line 2, and line 1 is wrong.

IndentationError

IndentationError: expected an indented block after 'if' statement on line 4

A block opened and nothing was indented under it, or indentation is inconsistent.

The nastiest version is invisible: mixed tabs and spaces. The code looks aligned and is not. This is why the VS Code lesson had you switch on whitespace rendering; turn it on now if you skipped it.

TabError: inconsistent use of tabs and spaces in indentation is the explicit form of the same problem.

NameError

NameError: name 'totl' is not defined

You used a name Python has never been told about. Three causes, in order of likelihood:

  1. A typo. Read the name in the message carefully — it is quoted exactly.
  2. Order. You used it on a line that runs before the line defining it. Functions and variables must be defined before use.
  3. Scope. It exists, but inside a different function.

UnboundLocalError is a specialised relative, covered in the scope lesson: you assigned to the name somewhere in the function, which made it local everywhere in that function.

TypeError

TypeError: can only concatenate str (not "int") to str

An operation was given the wrong type. The classics:

"I am " + 25                    # str + int
len(42)                         # len() of a number
None + 1                        # something returned None
"5" * "3"                       # two strings
sorted([1, "two"])              # cannot compare types

TypeError: 'NoneType' object is not subscriptable and 'NoneType' object has no attribute 'x' deserve special mention. NoneType in a TypeError almost always means a function returned None and you used the result. Look for a .sort(), .append() or similar whose result you assigned, or a function missing a return.

Also common:

TypeError: greet() missing 1 required positional argument: 'city'
TypeError: greet() takes 2 positional arguments but 3 were given

Wrong number of arguments. The message names the function and the parameter, which usually solves it outright.

ValueError

ValueError: invalid literal for int() with base 10: 'abc'

The type was right, the value was not. int() wants a string, and got one — but that string does not contain a number.

The distinction from TypeError is worth holding on to:

int("abc")      # ValueError — a string, but not a numeric one
int(None)       # TypeError  — not a string at all

Other frequent ones:

int("")                         # ValueError — empty string
int("12.5")                     # ValueError — int() will not take a decimal
[1, 2].remove(99)               # ValueError — not in list
a, b = [1, 2, 3]                # ValueError — too many values to unpack

That last one appears when data is not the shape you assumed — a CSV row with four fields instead of three, say.

KeyError

KeyError: 'email'

That key is not in that dictionary. Always. The message is the key.

Causes:

  • A typo or different capitalisation — "Email" is not "email"
  • The data genuinely did not include that field
  • You assumed an API response shape that is not guaranteed

The fix is .get() with a default when absence is normal, or try/except KeyError when it is not. Both are in the next lesson.

IndexError

IndexError: list index out of range

That position does not exist. Nearly always one of:

  • Off by one — valid indexes stop at len(list) - 1
  • The list is empty and you asked for [0]
  • You modified the list while looping over it

string index out of range is the same thing on a string.

AttributeError

AttributeError: 'list' object has no attribute 'push'

You called a method the object does not have. Either you have the wrong method name — push is JavaScript, append is Python — or you have the wrong type of object than you thought.

'str' object has no attribute 'append'      # this is a string, not a list
'NoneType' object has no attribute 'strip'  # it is None; something returned None

When surprised, check what the thing actually is:

print(type(value), repr(value))

repr() shows quotes and escapes, so you can see whether value is 5 or "5", and whether that string has a trailing newline.

ZeroDivisionError

ZeroDivisionError: division by zero

Almost always an average over an empty collection:

average = sum(numbers) / len(numbers)      # boom when numbers is empty

Guard it:

average = sum(numbers) / len(numbers) if numbers else 0

ModuleNotFoundError

ModuleNotFoundError: No module named 'requests'

Python cannot find that module. Usually:

  • Not installed — pip install requests

  • Installed into a different Python than the one running. The single most common cause, and the reason virtual environments exist (module 8). Check which Python you are actually on:

    python -c "import sys; print(sys.executable)"
    
  • Your own file is named after the module. A file called random.py in your folder shadows the standard library's random, and the failure is baffling. Never name a file after something you import.

RecursionError

RecursionError: maximum recursion depth exceeded

A function called itself with no way to stop. Even if you have not written recursion deliberately, this appears when two functions call each other in a loop.

A quick diagnosis table

Message contains Look for
NoneType A function that returned None
not defined A typo, or use before definition
not subscriptable Indexing something that is not a list, string or dict
not callable Brackets on something that is not a function — often a shadowed built-in
unhashable type A list used as a dict key or set item
not enough values to unpack Data is a different shape than assumed
object is not iterable Looping over a number or None

Practice

Trigger each deliberately, then fix it. Say the cause out loud before fixing.

  1. SyntaxError from a missing colon, then from an unclosed bracket. Note the reported line in the second case.
  2. IndentationError.
  3. NameError from a typo, then from using a variable one line too early.
  4. TypeError from "age: " + 25, then from calling a function with too few arguments.
  5. ValueError from int("abc"), then from unpacking three values into two.
  6. KeyError, then rewrite the line with .get().
  7. IndexError on an empty list.
  8. AttributeError by calling .push() on a list.
  9. ZeroDivisionError by averaging an empty list, then guard it.
  10. Create a file called random.py containing import random, run it, and read the confusing failure. Then rename it and appreciate why the rule exists.

Next: handling these deliberately instead of letting them stop your program.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship