RizTech Academy logo
RizTech Academy
Errors and DebuggingLesson 1 of 520 min

How to read a traceback

A traceback is the wall of text Python prints when something goes wrong. Most beginners glance at it, feel a small wave of dread, and scroll back to their code to guess. That is the expensive habit this lesson removes.

A traceback is not a complaint. It is a report telling you what went wrong, where, and how the program got there — usually enough to fix the problem without looking at anything else.

A simple one

numbers = [1, 2, 3]
print(numbers[5])
Traceback (most recent call last):
  File "/home/priya/app.py", line 2, in <module>
    print(numbers[5])
          ~~~~~~~^^^
IndexError: list index out of range

Four pieces of information, and you read them from the bottom.

IndexError: list index out of range — the last line is the actual problem. Error type, then a message. Read this first, always.

print(numbers[5]) — the line that failed, quoted back at you.

~~~~~~~^^^ — Python 3.11 and later point at the exact part of the line that broke. On a line with several operations this is genuinely valuable.

File "/home/priya/app.py", line 2 — where.

So: something asked for a list index that does not exist, on line 2, in numbers[5]. You now know the fix without re-reading anything.

Why it is called a traceback

Errors usually happen several calls deep:

def get_average(numbers):
    return sum(numbers) / len(numbers)

def report(data):
    average = get_average(data)
    print(f"Average: {average}")

report([])
Traceback (most recent call last):
  File "/home/priya/app.py", line 8, in <module>
    report([])
  File "/home/priya/app.py", line 5, in report
    average = get_average(data)
  File "/home/priya/app.py", line 2, in get_average
    return sum(numbers) / len(numbers)
           ~~~~~~~~~~~~~^~~~~~~~~~~~~~
ZeroDivisionError: division by zero

That is the call stack — the path Python took to reach the failure, oldest first.

  • Line 8 called report([])
  • which on line 5 called get_average(data)
  • which on line 2 divided by zero

"Most recent call last" is the important phrase. The bottom frame is where it broke. The frames above tell you how you got there.

Where the bug actually is

The error happened in get_average. The bug might not be.

get_average is arguably fine — dividing by the length of an empty list is a reasonable thing to fail on. The real question is why report was called with an empty list, and the traceback hands you that: line 8.

Read from the bottom to find where it broke. Read upwards to find why. That second half is the part beginners skip, and it is where most real bugs live.

Reading your own frames first

In a real project the stack includes library code:

Traceback (most recent call last):
  File "/home/priya/app.py", line 42, in <module>
    response = requests.get(url)
  File "/usr/lib/python3/requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
  File "/usr/lib/python3/requests/sessions.py", line 529, in request
    prep = self.prepare_request(req)
  ...
MissingSchema: Invalid URL 'example.com': No scheme supplied.

Twenty frames, eighteen of them inside requests. The library is almost certainly not broken.

Scan for the last line that mentions a file you wrote. Here that is line 42 of app.py, and the message confirms it: the URL needed https://. The intervening frames are how the library discovered your mistake, not evidence of its own.

The two-part error line

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

The type before the colon tells you the category, and each has a consistent meaning:

  • ValueError — right type, unusable value
  • TypeError — wrong type entirely
  • KeyError — that key is not in that dictionary
  • IndexError — that position is not in that sequence
  • AttributeError — that object has no such method or attribute
  • NameError — that name has not been defined
  • ZeroDivisionError — self-explanatory

Recognising the type usually narrows the cause before you read anything else. The next lesson goes through them properly.

The message after the colon is the specific detail. Note that this one quotes the offending value — 'abc'. Error messages often contain the actual data that broke, which saves you adding a print to find out.

"During handling of the above exception"

Sometimes you get two tracebacks joined:

Traceback (most recent call last):
  File "app.py", line 3, in <module>
    value = data["count"]
KeyError: 'count'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "app.py", line 5, in <module>
    print(f"Count: {count}")
NameError: name 'count' is not defined

Read the first one. The second happened while dealing with the first and is usually a consequence. Fix the top, and the bottom often disappears.

You will also see "The above exception was the direct cause of the following exception", which means the same thing more deliberately — code caught one error and raised another. That is raise ... from ..., in the raising lesson.

Tracebacks in a loop

When the same error appears a thousand times, scroll to the first. The ones after it are frequently caused by the first leaving something in a bad state.

Making them useful to future you

Two habits pay off immediately.

Do not screenshot a traceback — copy the text. You can search it, and the exact wording is what a search engine or a colleague needs.

When asking for help, include the whole thing. "I get a KeyError" is almost unanswerable. The full traceback contains the file, the line, the call path and the offending key.

Practice

For each, trigger the error deliberately, read the traceback aloud, and say which line is the cause rather than the site of the failure.

  1. print([1, 2, 3][10])

  2. print(int("abc"))

  3. print({"a": 1}["b"])

  4. print("5" + 5)

  5. print(undefined_variable)

  6. print("hello".push("x"))

  7. Write the three-function report([]) example. Identify which frame is the failure and which is the bug.

  8. Write a function calling a function calling a function, with the innermost failing. Count the frames and confirm the order.

  9. Take a traceback from question 7 and write down, in one sentence each: what broke, where, and why it was called that way.

  10. Cause an error inside a for loop running ten times. Notice the program stops at the first one — Python does not carry on and collect the rest.

Next: the specific errors you will meet most, and what each one usually means in practice.

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