Level 1 · First Words

Reading Errors Without Fear 🚨

This is the most valuable lesson in Level 1. Not because errors are interesting, but because the gap between a beginner and a competent programmer is mostly the speed at which they read an error message.

An error is a bug report written for you, by the machine, instantly, for free

Nobody writes correct code first time. Not you, not anyone. What separates people is that experienced programmers glance at the error, mutter something, and fix it in four seconds, while beginners feel a jolt of dread and start changing things at random.

The dread is unnecessary. The message contains the answer. Here is how to read it.

Anatomy of a traceback

Traceback (most recent call last):
  File "adventure.py", line 12, in <module>
    show_room(rooms[3])
              ~~~~~^^^
IndexError: list index out of range
LineWhat it is telling you
Traceback (most recent call last)A list of what called what. The last entry is where it actually broke
File "adventure.py", line 12Exactly where to look
show_room(rooms[3])The line itself
~~~~~^^^Which part of the line went wrong. Python 3.11 added these and they are wonderful
IndexErrorThe category of problem
list index out of rangeThe specific problem, in English
COMPOSURE[Medium: Success]

Read the bottom line first. Then the file and line number. Then, only if you still need it, the middle. Most beginners read top to bottom, get lost in the call stack, and never reach the sentence that explains everything.

The eight you will actually meet

1. SyntaxError: it is not valid Python

print("hello"
  File "hello.py", line 1
    print("hello"
         ^
SyntaxError: '(' was never closed

Caught before anything runs. Almost always a missing bracket, quote or colon. Key insight: look at the line above the one Python names. An unclosed bracket on line 8 is often only noticed on line 9.

2. IndentationError: your spacing is wrong

  File "game.py", line 4
    print("inside")
    ^
IndentationError: expected an indented block after 'if' statement on line 3

You wrote a colon and then did not indent, or indented inconsistently. Four spaces, no tabs.

3. NameError: you used a name that does not exist

score = 10
print(scroe)
NameError: name 'scroe' is not defined. Did you mean: 'score'?

Ninety percent of the time: a typo. Python 3.12 even suggests the correction. The other ten percent: you used a variable before creating it, or created it inside a function and tried to use it outside (Lesson 19).

4. TypeError: right idea, wrong kind of thing

print("Total: " + 42)
TypeError: can only concatenate str (not "int") to str

The fix is usually a conversion or an f-string:

print("Total: " + str(42))
print(f"Total: {42}")
Total: 42
Total: 42

5. ValueError: right type, impossible value

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

A string is exactly what int() wants; that particular string is not a number. This is the error that user input causes, constantly.

6. IndexError: past the end

crew = ["Guybrush", "Elaine", "Otis"]
print(crew[3])
IndexError: list index out of range

Three items means positions 0, 1 and 2. The last is always len(x) - 1, or simply x[-1]. This is the classic off-by-one.

7. KeyError: no such dictionary key

KeyError: 'captain'

You asked a dictionary for something it does not have. Lesson 13 shows you .get(), which returns a default instead of exploding.

8. AttributeError: that thing cannot do that

number = 42
number.upper()
AttributeError: 'int' object has no attribute 'upper'

.upper() is a string thing. Numbers do not have it. This one usually means a variable is not holding the type you thought it was, which makes it a good moment to print(type(x)) and find out.

A method that always works

When the message alone is not enough, do not start changing lines at random. Do this instead. It is slower for thirty seconds and faster for the next two hours.

  1. Read the last line. Out loud if necessary. It names the problem.
  2. Go to the file and line number. Look at that line, and the one above it.
  3. Print what you assumed. The bug is always in the gap between what you believe and what is true. Make the belief visible:
    row = "12,Guybrush,pirate"
    parts = row.split(",")
    
    print(f"{parts=}")
    print(f"{len(parts)=}")
    print(f"{type(parts[0])=}")
    parts=['12', 'Guybrush', 'pirate']
    len(parts)=3
    type(parts[0])=<class 'str'>
  4. Cut the program in half. Does the first half do what you expect? Then the bug is in the second half. Repeat. Ten halvings finds a bug in a thousand lines.
  5. Explain it to a duck. Out loud, line by line, to a rubber duck or a houseplant. You will very often catch it yourself mid-sentence. This is a real, named, widely used technique.
RUBBER DUCK[Easy: Success]

Go on. Tell me what line four does. No, not what it is supposed to do. What it does.

...ah. You did not expect that either, did you.

When you genuinely need help

A good question gets an answer in minutes. A bad one gets silence. The difference:

IncludeWhy
What you are trying to doOne sentence of context
The smallest code that shows the problemNot your whole file. Cut it down; you will often solve it while cutting
The full error message, as textNot a screenshot, not just the last line
What you already triedStops people repeating your work
Your Python versionpython3 --version

The act of writing that up solves the problem outright often enough to have a name: it is why Stack Overflow's "ask a question" page is the world's most effective debugger.

🤖 On asking an AI

Modern language models are genuinely good at reading tracebacks, and it is fine to use one. Two rules keep it from rotting your skill: read the error yourself first and form a hypothesis, and make it explain rather than just fix. 'Why did this happen' teaches you something; 'give me the corrected code' teaches you nothing and you will meet the same bug next week. Level 6 has you build your own assistant, which makes this even more tempting, so the habit is worth forming now.

Exercise 1

Diagnose without running

For each, name the exception type and the fix.

# A
print("Result: " + 10)

# B
name = input("Name: ")
print(nmae)

# C
numbers = [1, 2, 3]
print(numbers[3])

# D
print(int("3.5"))
Reveal solution

A: TypeError. Use f"Result: {10}" or str(10).

B: NameError. nmae is a typo for name.

C: IndexError. Three items live at 0, 1, 2. Use numbers[-1] for the last one.

D: ValueError. int() will not parse a decimal point in a string. Use int(float("3.5")), which gives 3.

Exercise 2

Fix the whole program

Four bugs. Find them by running it and reading each error in turn, fixing one at a time. Resist the urge to fix them all at once by eye.

crew = ["Guybrush", "Elaine", "Otis"]

print("Crew size: " + len(crew))

for i in range(4):
    print(crew[i])

if len(crew) > 2
    print("A full crew")
Reveal solution

In the order Python finds them:

  1. SyntaxError: the if line has no colon. Syntax errors are found before anything runs, so this one comes first even though it is last in the file.
  2. TypeError: "Crew size: " + len(crew) adds text to a number.
  3. IndexError: range(4) reaches index 3, and there are only three crew.
  4. Not an error, but a design bug: hard-coding 4 instead of using len(crew) means adding a crew member silently breaks the program.
crew = ["Guybrush", "Elaine", "Otis"]

print(f"Crew size: {len(crew)}")

for name in crew:
    print(name)

if len(crew) > 2:
    print("A full crew")
Crew size: 3
Guybrush
Elaine
Otis
A full crew

Note the final version does not just fix the errors, it removes the possibility of two of them. for name in crew cannot go out of range, ever. That is the difference between fixing a bug and fixing a class of bugs.

🎉 That is Level 1

You now know printing, variables, numbers, text, input, booleans, decisions, both kinds of loop, and how to read an error. That is genuinely enough to write useful programs. Take the Level 1 quiz, warm up in the Snake Pit, then go and build the first two projects before Level 2. Reading about programming and doing it are different skills, and only one of them is the job.

+100 XP