When building Python applications, it's a given that you'll run into errors.
Learning to identify and fix these errors is essential for effective debugging,
time-saving, and more importantly, avoiding such errors in the future.
This article presents a collection of 15 frequent Python errors and their
solutions. Although this list doesn't encompass all possible Python errors, it
aims to acquaint you with common problems, equipping you to deal with them as
they arise.
1. SyntaxError
SyntaxError is a common error that occurs when the Python interpreter parses
your code and finds incorrect code that does not conform to the syntax rules.
Some common causes of SyntaxError include:
Unclosed strings
Indentation issues
Misusing the assignment operator (=)
Misspelling Python keywords
Missing brackets, parentheses, or braces
Using newer Python syntax on an old version of Python.
When this error occurs, a traceback is produced to help you determine where the
problem is. Take the following example:
Copied!
employees = {"pam" 30,
"jim": 28}
for name, age in employees.items():
print(f"{name.capitalize()} is {age} years old.")
On line 1, the syntax is invalid because the dictionary's first property lacks a
colon (:) to separate the property "pam" and the value 30. When the code
is executed, the following traceback is produced:
Output
File "/home/stanley/code_samples/main.py", line 1
employees = {"pam" 30,
^^^^^^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?
The traceback message has multiple carets (^) showing where the invalid syntax
was encountered. While it sometimes might not pinpoint the exact location, it
will usually hint at the issue's probable location.
To address this issue, carefully consider the following information in the
traceback:
File name
Line number
Location indicated by the caret (^)
Error message, which can offer insights into the nature of the problem.
The question added at the end of the error message provides valuable context.
To catch syntax errors before you execute the code, configure a linter within
your code editor, such as Pylint,
Flake8 to statically analyze the code.
In the screenshot below, Pylance is used to highlights problematic areas with a
red underline in VS Code:
2. IndentationError
The IndentationError occurs in Python when there's an indentation issue in
your code. Common causes include mixing tabs with spaces, incorrect spacing,
incorrectly nested blocks, or whitespace at the beginning of a statement or
file.
Consider the following example:
Copied!
if True:
print("Incorrectly indented")
This triggers a Python traceback similar to:
Output
File "/home/stanley/code_samples/main.py", line 2
print("Missing colon")
^
IndentationError: expected an indented block after 'if' statement on line 1
To address and prevent this issue, use an editor or IDE configured with
formatters like Black, which auto-formats your
code as you write. The previously mentioned Pylance linter can also help you
identify indentation errors:
3. NameError
Python raises a NameError if you attempt to use an identifier that hasn't been
defined or might be out of scope. Other potential causes of a NameError
include referencing a variable before its assignment or misspelling an
identifier:
Copied!
print(name)
In this example, the name variable is not defined but is being accessed. As a
result, Python throws an exception:
Copied!
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
print(name)
NameError: name 'name' is not defined
To fix this problem, ensure that the variable or function name you want to use
has been defined. Check for spelling errors and ensure that the variable you
want to use is within the scope where it is being accessed.
Again, setting up a linter in your editor will help you catch such problems
error early in the development process:
4. ValueError
The ValueError exception indicates that a function received an argument of the
correct data type; however, the value itself is invalid. For example, the
int() method accepts only integer string like "42", and passing something
like "forty-two" will yield a ValueError:
Copied!
num = int("forty-two")
This leads to Python throwing an exception like this:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
num = int("forty-two")
ValueError: invalid literal for int() with base 10: 'forty-two'
Another common cause is passing an empty iterable to the max() or min()
built-in functions, e.g., max([]).
To resolve this issue, provide the correct data type and value as an argument to
the built-in functions. Check the documentation for the specific function you're
using to ensure compliance with expected input formats.
If applicable, consider using try-except blocks, to gracefully manage
potential user input errors and prevent ValueError occurrences that bring down
your entire program.
5. UnboundLocalError
The UnboundLocalError often occurs when you use a local variable within a
function or method before assigning a value to it. For example, referencing the
name variable before setting its value:
Copied!
def display_name():
print(name)
name = "John"
display_name()
You will see an exception resembling this:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 5, in <module>
display_name()
File "/home/stanley/code_samples/main.py", line 2, in display_name
print(name)
UnboundLocalError: local variable 'name' referenced before assignment
Other common causes for this error include:
A local variable in a function having the same name as a global variable,
known as
shadowing a global variable.
Using the del operator on a local variable that you referenced later.
To fix UnboundLocalError:
Assign values to local variables before referencing them.
If caused by shadowing a global variable, use a name different from the global
variable.
Avoid using the del operator on variables you will reference later.
6. TypeError
A TypeError exception in Python indicates that you are performing an operation
that is not supported or appropriate for the object data type. For example,
trying to divide a string with an integer:
Copied!
print("hello" / 3)
This produces an exception that looks like the following:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
print("hello" / 3)
TypeError: unsupported operand type(s) for /: 'str' and 'int'
This exception can also occur in situations like trying to loop over a
non-iterable (such as a float or integer) or using incorrect argument types for
built-in methods (like passing an integer to len(), which expects an
iterable). Furthermore, calling a function with fewer arguments than required or
comparing different data types can also lead to a TypeError.
To avoid these errors, ensure the following:
Only iterate through iterable sequences.
Use arguments that match the expected types in built-in functions.
Supply the correct number of arguments when calling a function.
Compare or convert to a common type when dealing with different data types.
See what happened right before a Python error
A traceback tells you where things broke, but logs tell you what led up to it. Centralize logs from all your Python services so you can search across deployments, correlate failures, and set alerts for repeating errors.
Better Stack makes this easy with fast search and built in monitoring.
7. UnicodeError
A UnicodeError exception is raised when Python encounters encoding or decoding
issues. The reasons for this error include:
Conflicts due to mixed encoding in the text.
Incorrect byte order marks (BOM) leading to decoding errors.
Use of unsupported or mismatched encoding schemes.
Conflicts arising from different Unicode standards.
Problems with surrogate pairs in UTF-16.
Corrupted or incomplete byte sequences.
Consider this example where decoding a Unicode string with ASCII results in an
error:
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 3, in <module>
print(decoded_str.decode('ascii'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe1 in position 0: ordinal not in range(128)
To mitigate such issues, use a reliable encoding like UTF-8 and ensure strings
are valid Unicode. Implementing error-handling strategies like try-except blocks
can also help manage encoding errors. Additionally, pay attention to Byte Order
Marks when working with files or data streams, and inspect the encoding and
character standards of external data sources.
8. ZeroDivisionError
Python raises the ZeroDivisionError exception when you attempt to divide a
number by zero:
Copied!
result = 5 / 0
print(result)
Python will throw the following exception:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
result = 5 / 0
ZeroDivisionError: division by zero
To fix this, avoid dividing numbers by zero. A strategy you can use is to check
if the divisor is zero:
Copied!
numerator = 5
denominator = 0
if denominator != 0:
result = numerator / denominator
else:
print("Division by zero avoided.")
This way, you can prevent the ZeroDivisionError by ensuring that the
denominator is not zero before performing the division.
9. FileNotFoundError
Python throws this exception when it attempts to perform file-related
operations, such as reading, writing, or deleting a file that does not exist in
the given location:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
with open('file_does_not_exist.txt', 'r') as file:
FileNotFoundError: [Errno 2] No such file or directory: 'file_does_not_exist.txt'
To fix this, ensure that the file exists at the given location. Also,
double-check the file path, file extension, and take into account relative or
absolute paths to the file.
Often, the program might receive incorrect file paths from users, which is
beyond your control. A good solution is to use a try-except block to handle
the FileNotFoundError so that the program doesn't crash:
Copied!
file_path = 'file_does_not_exist.txt'
try:
with open(file_path, 'r') as file:
content = file.read()
# Additional file processing code can go here
except FileNotFoundError:
print(f"The file '{file_path}' does not exist.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
This way, you can gracefully handle the absence of a file and prevent the
program from crashing.
10. ModuleNotFoundError
Python raises the ModuleNotFoundError when it can't import a module. This
issue may arise if the module isn't installed on your system or in the virtual
environment. Sometimes, the error could be due to an incorrect module path or
name. Additionally, this error occurs when importing from a package that lacks a
__init__.py file.
An example of this error's traceback is:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
import arrow
ModuleNotFoundError: No module named 'arrow'
To resolve this, first check if the module is installed, using pip for
third-party modules. Secondly, verify the accuracy of the module name and file
path, as errors here can lead to this issue. Lastly, ensure that Python packages
contain a __init__.py file, necessary for Python to recognize them as valid
packages.
11. MemoryError
A MemoryError in Python occurs when the system runs out of memory. This is
often caused by memory leaks where memory is continuously consumed without being
released, or by loading large files entirely instead of in smaller chunks.
For example, this code attempting to create a list with over a billion elements:
Copied!
large_list = [0] * (10**9) # Attempting to create a list with more than a billion elements
leads to a MemoryError:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 1, in <module>
large_list = [0] * (10**9) # Attempting to create a list with more than a billion elements
MemoryError
To handle this, use memory profiling tools like Scalene to pinpoint the
memory-intensive parts of your program.
For Python servers, an interim fix could be setting up an auto-restart mechanism
that activates when memory usage crosses a certain limit. This approach can
temporarily alleviate memory leaks by periodically freeing up memory.
For large file operations, read files in smaller chunks. If the file is
line-based, iterate over discrete lines:
Copied!
with open("large_file.txt") as file:
for line in file:
print(line)
For single-line large files, consider using a Python generator. This method is
detailed in
this Stack Overflow post
on processing large text files.
Catch Python exceptions in production with full context
Fixing errors locally is useful, but production failures need fast visibility. Better Stack Error Tracking groups exceptions, highlights the most frequent stack traces, and can alert you on Slack or email when errors spike.
Start free and see your first grouped issues in minutes.
12. PermissionError
Python raises a PermissionError when it tries to execute an operation without
the required privileges, such as accessing or modifying restricted files or
directories. This error can also occur if a file is currently in use by another
program.
For example, trying to create a directory in a protected area like /etc:
Copied!
import os
os.mkdir("/etc/new_directory")
results in the following traceback:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 3, in <module>
os.mkdir("/etc/new_directory")
PermissionError: [Errno 13] Permission denied: '/etc/new_directory'
To address a PermissionError, consider running your script with elevated
privileges using sudo, but be cautious as it can be risky.
Other solutions include modifying file or directory permissions with
os.chmod(), adjusting
ACLs using
setfacl, or moving the file/directory to a location with write permissions
using shutil.move(). The right solution here depends on your specific needs
and security considerations.
13. IndexError
An IndexError is often encountered when you attempt to access an index in a
sequence, such as a list, tuple, or string, and it is outside the valid range.
For instance, trying to access index 4 in a list with only three elements:
Copied!
numbers = [10, 20, 30]
numbers[4]
results in the following exception:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 2, in <module>
numbers[4]
~~~~~~~^^^
IndexError: list index out of range
To prevent IndexError, ensure that the index you're accessing falls within the
sequence's valid range. This can be checked by comparing the index with the
sequence's length, obtainable using the len() method.
Copied!
numbers = [10, 20, 30]
# Ensure the index is within the range of the list
index = 4
if index < len(numbers):
print(numbers[index])
14. KeyError
A KeyError in Python is raised when an attempt is made to access a dictionary
value using a key that doesn't exist. This error can occur if the key is
missing, if there's a typographical error, or if the dictionary is empty:
Copied!
my_dict = {'name': 'John', 'age': 25}
print(my_dict['location']) # the 'location' key does not exist
The error message produced looks like this:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 2, in <module>
print(my_dict['location']) # the 'location' key does not exist
~~~~~~~^^^^^^^^^^^^
KeyError: 'location'
To avoid a KeyError, verify the presence of the key in the dictionary and
ensure there are no typos. Alternatively, use the dict.get() method, which can
return a default value if the key is not found:
For a more robust approach, use get() and handle the result accordingly:
Copied!
my_dict = {'name': 'John', 'age': 25}
location = my_dict.get('location')
if location is not None:
print("Location:", location)
else:
print("Location key not found in the dictionary.")
15. AttributeError
An AttributeError in Python is raised when there's an attempt to access or
utilize an attribute that an object or class doesn't possess. For instance,
since a list lacks the lower() method:
Copied!
my_list = [1, 2, 3]
print(my_list.lower())
This attempt results in the following error message:
Output
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 2, in <module>
print(my_list.lower())
^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'lower'
To prevent this error, ensure that you're using attributes and methods that are
actually available for the given object. This can be confirmed by consulting the
object's documentation. Additionally, verify the correct spelling of the
attribute names.
You can also use tools like Mypy for static analysis
to detect such issues early. Mypy would indicate a problem in the above code as
follows:
Output
main.py:2: error: "list[int]" has no attribute "lower" [attr-defined]
Found 1 error in 1 file (checked 1 source file)
Dealing with Python errors in production
While we have explored common Python errors and their solutions, it is important to recognize that errors are inevitable in any sufficiently complex program. What matters in production is how quickly you can answer three questions: what broke, where it is happening, and what changed.
A practical way to shorten that loop is to pair good application logging with a setup that centralizes and visualizes your logs, so you can investigate incidents without SSHing into boxes or hunting for the right file.
Python offers several logging frameworks you can integrate into your application. Here is a minimal example using the standard library:
Once your app is producing useful logs, the next step is shipping them somewhere central so they are searchable and available even if a server dies or a container restarts. That is where a collector helps.
Ship logs reliably with a collector
In production you want log shipping to be boring. A collector runs alongside your application, collects logs from the sources you care about, enriches them with helpful metadata like host, service, and environment, and forwards everything to a central place. This is what makes it possible to debug across multiple machines, keep a consistent format, and avoid losing logs during spikes.
Follow incidents in real time with Live Tail
Once logs are centralized, you can go beyond tailing a single file or running journalctl --follow on one server. Live Tail lets you watch events in real time across all machines, filter as new logs arrive, and jump into surrounding context with a click. It is ideal for active incidents, deploy verification, and tracking down intermittent errors.
Visualize patterns so you can spot spikes and trends
After the incident is contained, the next challenge is understanding impact and preventing repeats. Visualizations help you move from individual log lines to higher level signals: error rate over time, top exception messages, which hosts are affected, and whether a regression started right after a release. Instead of searching manually, you can turn recurring questions into dashboards and keep an eye on trends.
If you want to try it, sign up for a free account, connect your first source, and you will have a single place to collect, live tail, and visualize your production errors.
Final thoughts
Understanding the common causes of Python errors and how to address them is
crucial for efficient problem-solving. In this article, we explored 15 common
errors in Python and discussed various strategies to resolve them.
For further exploration,
the Python documentation
offers detailed information on exceptions and custom exception creation.
You should also check out our logging guides for further guidance on
how to create a comprehensive logging strategy for your Python applications.