← Learning center

Understanding Python error messages and stack traces

IIt's important to understand what your application's error type is telling you when debugging an issue.

In this article, we'll cover common Python error types and what your application tells you when encountering one.

How to read an error message

Error messages are most often output in the following format:

python
File, line 1, Context ErrorType: error message

For example, considering the following example:

python
File "/../maths_is_hard.py", line 1, in <module> print(f"{x} divided by {y} is {x / y}") NameError: name 'x' is not defined

We can deduce the following:

  1. Error location: line 1 of the maths_is_hard.py file
  2. Error type: NameError
  3. Error Message: name 'x' is not defined

Which can be understood as: "On line 1, of the maths_is_hard.py file, an undefined x variable was used."

How to read a stack trace

Whenever an error occurs in your application, Python will raise an exception and log a stack trace, which you can then use to find the location of an error within your application's code.

In Python, if you try and divide a number by zero, you will raise a ZeroDivisionError. To demonstrate a stack trace, let's raise one:

python
# maths_is_hard.py def divide(x, y): print(f"{x} divided by {y} is {x / y}") divide(8, 0)

In the above code snippet, we've created a function called divide(a, b), which will divide any two integers we provide it. Let's run the code in our terminal to raise ZeroDivisionError and print a stack trace:

python
$ python maths_is_hard.py Traceback (most recent call last): File "/home/runner/python-test-repo/maths_is_hard.py", line 8, in <module> divide(8, 0) File "/home/runner/python-test-repo/maths_is_hard.py", line 3, in divide print(f"{x} divided by {y} is {x / y}") ZeroDivisionError: division by zero

So, what is our stack trace telling us? Let's look at it line per line:

  1. The first line tells us: On line 8 of maths_is_hard.py code was executed that resulted in a ZeroDivisionError, below the line it shows us the function: divide(0,8)
  2. The second line tells us: the error was raised on line 3 of the maths_is_hard.py file via the divide function. Indented, under, it shows us the code of that line.
  3. The third line tells us: the error type and error message.

We can use this stack trace to deduce where the error was raised in our code and where the method was called from. In the case of the example above, we know the issue was caused by 0 being passed as an argument on maths_is_hard.py:3. We could then make sure not to pass 0 as an argument or modify our method to safely return a message if 0 is passed as an integer:

python
# maths_is_hard.py def divide(x, y): if y > 0: print(f"{x} divided by {y} is {x / y}") else: print("You can't divide by 0") divide(8, 0)

Which would output the following when run:

shell
$ python maths_is_hard.py You can't divide by 0

Good to know: We're using shorter stack traces here for brevity, but your application's stack trace will often be much longer. However, the same logic to reading stack traces applies, regardless of length.

Common error types

KeyError

A KeyError occurs when trying to access a key that does not exist with dict[key], for example, when trying to access the non-defined indian key in the below python_breed_count dict:

python
> python_breed_count = { 'ball': 12, 'timor': 9, 'burmese': 2 } > python_breed_count['indian'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'indian'

Resolutions

Using in operator

We can use the in operator to check to see if a value is in a dict, and then execute specific logic when that condition is met:

python
if 'burmese' in python_breed_count: print(f"There are {python_breed_count['burmese']} snakes in the plane")

Using Dict

You can always list the available keys using the keys() function:

python
> python_breed_count.keys() dict_keys(['ball', 'timor', 'burmese'])

You could then use dict[key] to retrieve available key values:

python
> python_breed_count['burmese'] 2

However, as the KeyError example shows, an exception is raised when a key the dict does not contain is called:

python
> python_breed_count['carpet'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'carpet'

If we don't wish to raise an error in this use case, we can instead dict(key) to retrieve values. When a key is not present, none or a default value:

python
> python_breed_count = { 'ball': 12, 'timor': 9, 'burmese': 2 } # does not throw error, returns None if the key is not present > python_breed_count.get('indian') # does not throw error, returns 0 if the key is not present > python_breed_count.get('indian', 0) 0

NameError

A NameError is raised when calling an attribute or function that is not defined.

For example, we want to assign a string to the attribute, title only we make a typo and accidentally assign it to an attribute incorrectly named titel, meaning when we call title in our code, we raise a NameError, because title is not defined.

python
> titel = "Monty's Masterclass: Pythonic Puns and Pop Culture Parodies" > title Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'title' is not defined. Did you mean: 'titel'?

Resolution

To resolve this error, we need to make sure we are calling attributes and functions that are defined:

python
> title = "Monty's Masterclass: Pythonic Puns and Pop Culture Parodies" > title "Monty's Masterclass: Pythonic Puns and Pop Culture Parodies"

UnicodeError

UnicodeEncodeError and UnicodeDecodeError are raised when Python cannot encode or decode from or to Unicode.

In the below example, we're trying to encode the string piñata to ASCII. Because ASCII codec does not support the ñ character a UnicodeEncodeError is raised:

python
> partyGame = "Piñata" > encodedPartyGame = partyGame.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character '\xf1' in position 2: ordinal not in range(128)

As you can see in the above error, ñ, known in unicode as /xf1 cannot be encoded.

Resolution

A solution is to use a codec that supports the character you want to encode. Let's try in UTF-8:

python
> partyGame.encode('utf-8') b'Pi\xc3\xb1ata'

As you can see, piñata is successfully encoded into a UTF-8 byte string. Let's try and decode it:

python
encodedPartyGame.decode('utf-8') 'Piñata'

We may, however, also encounter a situation where you need to decode a byte_string via a specific codec and encounter an error due to an unsupported character:

python
> encodedPartyGame.decode('ascii') UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in range(128)

In this case, we can pass an error argument telling Python what to do when encountering a character it can't decode. The values are strict, replace, ignore, and backslashreplace. While strict will return a UnicodeDecodeError the other arguments allow you to handle the encoded character without raising an error:

python
> encodedPartyGame.decode('ascii', 'replace') 'Pi��ata' > encodedPartyGame.decode('ascii', 'ignore') 'Piata' > encodedPartyGame.decode('ascii', 'backslashreplace') 'Pi\\xc3\\xb1ata'

We can also try replacing non-supported characters before encoding:

python
> 'piñata'.replace('ñ', 'n').encode('ASCII') b'Pinata'

TypeError

A TypeError occurs when an object is the wrong type for the action you are attempting to execute. For example, when trying to add an integer to a string:

python
> "1" + 2 TypeError: can only concatenate str (not "int") to str

Resolution

As 1 is a string, it has no numerical value and can't be added to another integer. To be added successfully, it must first be converted into an integer, and we can do this using Python's int() function.

python
> int('1') + 2 3

Note that we can only convert textual representations of integers to integer objects, not strings. Trying to convert a string to an integer would raise a ValueError.

ValueError

A ValueError occurs when a function is called with the correct argument type but the wrong value.

For example, Python's int() function, which converts strings of integers into integer objects, expects a string argument. However, the string must be a textual representation of an integer:

python
> int('one') ValueError: invalid literal for int() with base 10: 'one'

Resolution

In this case, to resolve the error, we need to make sure we pass the correct value to the int() function:

python
> int('1') 1

If you need clarification on what values a function requires, access the function in your application or read the relevant documentation. For example, when looking at Python's documentation for the int() function we can read that by default, the function uses base 10, meaning the string can only contain digits between 0-9.

Never miss an exception with AppSignal

With AppSignal Error Reporting, AppSignal can record and notify you when errors occur, helping you quickly resolve problems in your application's codebase.

Graph showing Python error in AppSignal

AppSignal's Error Reporting is just one of our many developer-driven features that help you get the most out of monitoring your application. Developers also enjoy using our monitoring because we offer:

  • An intuitive interface that is easy to navigate.
  • Simple and predictable pricing.
  • Developer-to-developer support.

If you're ready to monitor your application's errors, start a free trial with AppSignal today!

Start your free trial

Don’t let the bad bugs bite. Try AppSignal for free.

AppSignal offers a 30-day free trial, no credit card is required. All features are available in all plans. Start monitoring your application in just a few clicks!