Command Palette

Search for a command to run...

Hectal
PHASE 0Beginner ~29 min· topic 7 of 8

Topic 0.7

Reading Error Messages and Tracebacks

In one line

When Python cannot run a line it stops and prints an error message. Read it from the bottom: the last line names the kind of error and what went wrong, and the lines above it (the traceback) show the file and line number where it happened.

Think of it like this

A parcel that could not be delivered. The courier does not just give up silently; a note says what went wrong ("house number not found") and where ("at step 3: Gandhi Road"). A Python error message is that note. It tells you what went wrong and where, and it is there to help you.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Error
Python's report that it could not do what the code asked.
Syntax error
A grammar mistake found before the program starts running.
Exception
An error that happens while the program is running.
Traceback
The report printed for an exception: the chain of lines that led to the error, ending with the error itself.
Error type
The category name at the start of the last line, such as TypeError or NameError.
Raise
What Python does when an error happens: it "raises" an exception, which stops the program unless something handles it.
Crash
A program stopping because of an error nobody handled.
Call
To run a named group of code (a function). print("hi") calls print.
Name
The label that stands for a value, such as count or print. Topic 1.1 teaches names and variables.

Step by step

01An error stops the program where it happens

This program has four lines. The third uses a name that doesn't exist. Lines 1 and 2 run and print; line 3 fails; line 4 never runs.

The traceback appears after the normal output, because the output had already been printed when the error happened.

main.pywhole filepython
print("Line 1 runs")
print("Line 2 runs")
print(undefined_name)
print("Line 4 never runs")
terminal
$ python main.py
── expected output ──
Line 1 runs
Line 2 runs
Traceback (most recent call last):
File "main.py", line 3, in <module>
print(undefined_name)
^^^^^^^^^^^^^^
NameError: name 'undefined_name' is not defined

02Read it from the bottom

Last line: NameError: name 'undefined_name' is not defined. The type is NameError; the message says which name. That alone usually tells you the fix.

Above it: File "main.py", line 3 gives the file and the line number. Then comes the line of code, and the ^ marks sit under the exact part Python could not handle. in <module> means the line is at the top level of the file, not inside a function.

Read it from the bottomdiagram
Rendering diagram…

03A syntax error: nothing runs

Here the first line would print fine, but the second has no closing quote. Python checks the grammar of the whole file before running any of it, so even Step 1 is never printed.

A syntax error has no Traceback header, because the program never started and there is no journey to trace. You get the file, the line, a ^ pointing at the spot, and the message.

main.pywhole filepython
print("Step 1")
message = "Hello
print(message)
terminal
$ python main.py
── expected output ──
File "main.py", line 2
message = "Hello
^
SyntaxError: unterminated string literal (detected at line 2)

04TypeError: the wrong kind of value

+ can add two numbers or join two pieces of text, but it will not join text to a number. The message says exactly that: it can only concatenate (join) str (text) to str, not int (a whole number).

The ~ marks underline the whole expression and the ^ marks the operator in the middle of it. The fix is to turn the number into text with str(count), or to give print the two values separated by a comma.

main.pywhole filepython
count = 3
print("Count: " + count)
terminal
$ python main.py
── expected output ──
Traceback (most recent call last):
File "main.py", line 2, in <module>
print("Count: " + count)
~~~~~~~~~~^~~~~~~
TypeError: can only concatenate str (not "int") to str

05A traceback with several steps

Real programs group code into functions (Phase 5): named blocks that call each other. You don't need to write one yet. def average(marks): makes a function named average, return hands its answer back, and sum and len are ready-made functions that add up the values and count them. Below, the last line of the file calls report, which calls average, which divides by zero when the list of marks is empty.

The traceback shows all three places, in the order they were called. Read the bottom entry first: line 3, inside average, dividing by len(marks). Then read upward to find out who called it with an empty list: line 9. The bottom shows where it broke; the lines above show how the program got there.

main.pywhole filepython
def average(marks):
    total = sum(marks)
    return total / len(marks)

def report(name, marks):
    print(name, "average:", average(marks))

report("Asha", [70, 80])
report("Ravi", [])
terminal
$ python main.py
── expected output ──
Asha average: 75.0
Traceback (most recent call last):
File "main.py", line 9, in <module>
report("Ravi", [])
~~~~~~^^^^^^^^^^^^
File "main.py", line 6, in report
print(name, "average:", average(marks))
~~~~~~~^^^^^^^
File "main.py", line 3, in average
return total / len(marks)
~~~~~~^~~~~~~~~~~~
ZeroDivisionError: division by zero

06The mistake may be one line up

Python reports the place where the code stopped making sense, which can be after the real mistake. Here the bracket is left open on line 1. Modern Python is good at this case and points back at the bracket, but with other mistakes it reports the following line.

Rule of thumb for a SyntaxError: look at the reported line, and if it looks fine, look at the line above.

main.pywhole filepython
total = (10 + 20
print(total)
terminal
$ python main.py
── expected output ──
File "main.py", line 1
total = (10 + 20
^
SyntaxError: '(' was never closed

07A method for every error

1. Read the last line: type and message. 2. Go to the line number. 3. Look at what the ^ marks point to. 4. Ask what you expected that line to do. 5. Change one thing and run again.

If the message itself is unclear, search for the type and the fixed part of the message (TypeError: can only concatenate str), without your own variable names. AI assistants are good at explaining an error too: paste the whole traceback and the code, and then check that you understand the explanation, because the goal is to recognise the error yourself next time.

Try it yourself

  1. 1

    Fix the NameError two ways

    In the first example, fix line 3 by adding quotes: print("undefined_name"). Run it. Then undo that and instead add a new line above it: undefined_name = 42. Run again. Both fixes work; they mean different things.

  2. 2

    Cause three errors on purpose

    In the first example, replace line 3 with each of these in turn and read only the last line of each error: print(10 / 0), then print(int("twelve")), then print("Total: " + 5). Match each to a row of the table.

  3. 3

    Trace the journey

    In the third example, change the last line to report("Ravi", [50]) and run it. No error now. Then put the empty list back and add print("Checking", name) as the first line inside report. Use the output to say which call fails.

Code & diagrams

An exception: lines before it run, lines after it don't New tab

The output shows two printed lines and then the traceback. Fix line 3 by putting quotes around the name, or by defining it first.

Sign in to run this example in your browser.

Expected output

Line 1 runs
Line 2 runs
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    print(undefined_name)
          ^^^^^^^^^^^^^^
NameError: name 'undefined_name' is not defined
A syntax error: nothing runs at all New tab

Step 1 is not printed, although its line is correct. Python checks the whole file's grammar first. Add the missing quote.

Sign in to run this example in your browser.

Expected output

  File "main.py", line 2
    message = "Hello
              ^
SyntaxError: unterminated string literal (detected at line 2)
A traceback with several steps New tab

Read the traceback from the bottom. Which line broke? Which line called it with an empty list? (def creates a named block of code; Phase 5 teaches it.)

Sign in to run this example in your browser.

Expected output

Asha average: 75.0
Traceback (most recent call last):
  File "main.py", line 9, in <module>
    report("Ravi", [])
    ~~~~~~^^^^^^^^^^^^
  File "main.py", line 6, in report
    print(name, "average:", average(marks))
                            ~~~~~~~^^^^^^^
  File "main.py", line 3, in average
    return total / len(marks)
           ~~~~~~^~~~~~~~~~~~
ZeroDivisionError: division by zero
The errors beginners meet mosttext
Error type            Usually means                               Example that causes it
SyntaxError           broken grammar: bracket, quote or colon     print("hi"
IndentationError      wrong spaces at the start of a line         an indented line with no colon above it
NameError             a name Python doesn't know (spelling?)      Print("hi")   or   print(nmae)
TypeError             wrong kind of value for this operation      "Count: " + 3
ValueError            right kind of value, but unusable           int("twelve")
IndexError            position beyond the end of a list           prices[3] when there are 3 prices
KeyError              a dictionary has no such key                user["age"] when only "name" exists
AttributeError        this kind of value has no such feature      "hello".push("!")
ZeroDivisionError     dividing by zero                            10 / 0
ModuleNotFoundError   import of a library that isn't there        import statistic

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Join text and a number

Build a sentence by adding a number to text with +.

main.pywhole filepython
age = 12
print("Next year you will be " + age + 1)
terminal
$ python main.py
── what you'll see ──
Traceback (most recent call last):
File "main.py", line 2, in <module>
print("Next year you will be " + age + 1)
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
TypeError: can only concatenate str (not "int") to str

Break #2

Ask a list for an item it doesn't have

Make a list of three prices and ask for the item at position 3.

main.pywhole filepython
prices = [30, 12, 8]
print(prices[3])
terminal
$ python main.py
── what you'll see ──
Traceback (most recent call last):
File "main.py", line 2, in <module>
print(prices[3])
~~~~~~^^^
IndexError: list index out of range

Break #3

Convert text that isn't a number

Ask int() to turn the word twelve into a number.

main.pywhole filepython
print("Step 1 done")
number = int("twelve")
print("Step 2 done")
terminal
$ python main.py
── what you'll see ──
Step 1 done
Traceback (most recent call last):
File "main.py", line 2, in <module>
number = int("twelve")
ValueError: invalid literal for int() with base 10: 'twelve'

Myth vs fact

Myth

An error message means I am bad at programming.

Fact

Every programmer sees errors all day. The message is information, and reading it calmly is the professional skill.

Myth

The line number always points at my mistake.

Fact

It points at where Python noticed a problem. The cause can be a line earlier, especially a missing bracket or quote, or in the code that called this line with bad values.

Myth

Long tracebacks are worse than short ones.

Fact

A long traceback is a more detailed map. The last line still says what went wrong; the rest shows the route, which is exactly what you need in a big program.

Myth

If I get an error, I should rewrite the whole thing.

Fact

Change one thing at a time, guided by the message. Rewriting hides what the problem was, and you will meet it again.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The ~ and ^ position markers come from PEP 657 (Python 3.11), which stores column offsets for every bytecode instruction. They are invaluable on lines such as a[i][j] + b[k], where older versions could not say which subscript failed.

  • ▸

    Since 3.10 the parser produces far more specific syntax messages ('(' was never closed, expected ':'), and NameError/AttributeError suggest close matches. If your errors look vaguer than the ones in this course, you are on an old Python.

  • ▸

    In production, uncaught exceptions should be logged with their full traceback (logging.exception, Topic 7.9) and usually sent to an error tracker. The traceback is the most valuable debugging artefact you have; never replace it with a bare "something went wrong".

  • ▸

    Exceptions can be chained: "During handling of the above exception, another exception occurred" and "The above exception was the direct cause" join two tracebacks. Read the first one to find the root cause (Topic 7.2).

Remember this

  1. 1

    There are two moments an error can appear. A syntax error is found before the program starts: Python reads the whole file first, and if the grammar is broken anywhere, nothing runs at all. An exception happens while the program runs: every line before the failing one has already run, and the lines after it never do.

  2. 2

    The text Python prints for an exception is a traceback. Read it from the bottom up. The last line has the error's type (such as NameError) and a message explaining it. Just above are the file name, the line number and the line of code itself, often with ^ or ~ marks under the exact part that failed.

  3. 3

    When one piece of code calls another, the traceback lists every step of the journey, in the order the calls were made, with the place where the error actually happened last. That is what "most recent call last" means in the first line.

  4. 4

    A handful of error types cover most beginner mistakes. **SyntaxError: broken grammar, such as a missing bracket or quote. IndentationError: wrong spaces at the start of a line. NameError: a name Python doesn't know, usually a spelling mistake. TypeError: the wrong kind of value, such as adding text to a number. ValueError**: the right kind of value but an unusable one, such as int("twelve"). **IndexError and KeyError: asking a list (a row of values, Phase 4) or a dictionary (values looked up by a label, Phase 4) for something that isn't there. ZeroDivisionError**: dividing by zero.

  5. 5

    The line Python points at is where it noticed the problem, which is not always where the mistake is. With syntax errors in particular, a missing bracket or quote is often on the line above the one reported.

  6. 6

    Reading errors is a skill, and it is the one that most separates people who get stuck from people who keep moving. The method is always the same: read the last line, go to the line number, compare what the code says with what you meant, change one thing, run again.

Explain it without notes

01

What is the difference between a syntax error and an exception?

02

In what order should you read a traceback, and what does each part tell you?

03

What does "most recent call last" mean?

04

Give the likely cause of each: NameError, TypeError, IndexError.

05

Why might the mistake not be on the line that the error reports?

Practice

01

This program should print Total: 50 but crashes. Read the error, then fix it: line 1 price = 25, line 2 total = price * 2, line 3 print("Total: " + total).

02

Without running it, say what this prints, including the error type: line 1 print("A"), line 2 print(10 / 0), line 3 print("B").

03

A program fails with NameError: name 'totl' is not defined. Did you mean: 'total'? on line 7. What is the most likely mistake, and how do you fix it?

Trade-offs

  • ↔

    Stopping at the first error vs carrying on. Python stops immediately, which can feel harsh but keeps a wrong value from spreading into later results. Languages or tools that carry on silently are harder to debug.

  • ↔

    Detailed vs short messages. Long tracebacks take practice to read, but each line answers a real question. Hiding them from developers makes problems slower to fix; hiding them from end users (while logging them) is good practice.

Done when you can

  • Done when you read the last line of an error first, without being told.

  • Done when you can find the file, line number and position marks in a traceback.

  • Done when you can explain why a syntax error stops every line from running.

  • Done when you can name the likely cause of NameError, TypeError, ValueError and IndexError.

  • Done when you can follow a three-step traceback from the failing line back to the call that caused it.