GICT knowledge base
How to Read Python Tracebacks and Fix the Underlying Error
Published
A Python traceback shows the call path leading to an exception. Start with the exception type and message at the bottom, then inspect the failing line and its callers. The line where a bad value is used is not necessarily where that value first became wrong.
This guide uses Python 3.12.14. Error wording, caret indicators and file paths can differ between versions and environments. The first example deliberately fails so you can read its actual traceback; the later examples distinguish recovery, logging and input validation.
Read a complete example from the bottom up
In trace_example.py, the caller supplies zero workers. Running it raises ZeroDivisionError; it is an intentionally failing example, not a successful calculation.
def per_worker(total, workers):
return total / workers
def summarize():
return per_worker(12, 0)
print(summarize())
Output captured from that script on Python 3.12.14, with the directory portion of each filename shortened:
Traceback (most recent call last):
File "trace_example.py", line 7, in <module>
print(summarize())
^^^^^^^^^^^
File "trace_example.py", line 5, in summarize
return per_worker(12, 0)
^^^^^^^^^^^^^^^^^
File "trace_example.py", line 2, in per_worker
return total / workers
~~~~~~^~~~~~~~~
ZeroDivisionError: division by zero
- Exception: The last line identifies division by zero.
- Failing expression: Line 2 divides
totalbyworkers. - Caller: Line 5 passed
0as the worker count. Changing the arithmetic alone would hide the input problem. - Entry point: Line 7 called
summarize(). Traceback frames appear in call order from the outer call toward the failure.
For a real incident, record the interpreter version, deployed code version and a minimal non-sensitive input that reproduces the failure. A log from yesterday may refer to different line numbers than today’s edited file.
Recognize common exception types
| Exception | What to inspect |
|---|---|
SyntaxError |
Grammar, unmatched delimiters or an earlier incomplete statement. A parse failure may show a source location without a normal runtime call stack. |
IndentationError / TabError |
Block alignment and mixed indentation. These are syntax-error subclasses. |
NameError |
A misspelled or unavailable name in the current scope. |
TypeError |
An operation or argument incompatible with its object type. |
ValueError |
A value that the operation cannot accept, such as int("many"). |
AttributeError |
An attribute or method the object does not provide. |
IndexError |
A sequence position outside its valid range. |
KeyError |
A missing mapping key. Use a default only if absence is actually acceptable. |
Do not expect two uncaught errors in one script to both run: execution stops at the first uncaught exception. Isolate each reproduction. A debugger’s call-stack and variable views can help, but avoid exposing passwords, tokens or customer records when sharing screenshots.
Preserve the cause when adding context
Catch a specific error only when you can recover or explain it meaningfully. raise ... from error retains the original cause instead of replacing it with an unrelated message.
def parse_count(text):
try:
value = int(text)
except ValueError as error:
raise ValueError("Job count must be a whole number") from error
if value < 0:
raise ValueError("Job count cannot be negative")
return value
assert parse_count("12") == 12
try:
parse_count("many")
except ValueError as error:
assert str(error) == "Job count must be a whole number"
assert isinstance(error.__cause__, ValueError)
else:
raise AssertionError("Invalid input was accepted")
print("The conversion error retained its cause")
This function expects text input. In a traceback with chained exceptions, read both the original failure and the new contextual error. A broad except Exception: pass discards the information you need and can make a broken job appear successful.
Log an exception explicitly, then preserve failure
logging.basicConfig() configures logging; it does not automatically catch exceptions. Call logger.exception() inside an exception handler to include the current traceback. This function re-raises after logging, allowing its caller to report failure rather than continue with a fabricated result.
import logging
logger = logging.getLogger("tutorial.job")
def parse_with_log(text):
try:
return int(text)
except ValueError:
logger.exception("Job count conversion failed")
raise
if __name__ == "__main__":
logging.basicConfig(level=logging.ERROR)
parse_with_log("many")
Running that block as a script intentionally exits with an error. In a larger application, configure handlers at the application boundary and avoid logging the same exception repeatedly at every layer. Traceback messages and paths may contain sensitive details even without dumping local variables; restrict log access and sanitize copies shared for support. Never publish a production debug traceback to visitors.
Validate real inputs without assert
Assertions are useful for tests and internal assumptions, but Python’s -O option can remove them. Use explicit checks and exceptions for a required input contract. Here the permitted count is a positive integer, excluding Boolean values.
def per_worker(total, workers):
if type(workers) is not int:
raise TypeError("workers must be an integer")
if workers <= 0:
raise ValueError("workers must be positive")
return total / workers
assert per_worker(12, 3) == 4
for invalid, expected in [(0, ValueError), (-1, ValueError),
(True, TypeError), ("3", TypeError)]:
try:
per_worker(12, invalid)
except expected:
pass
else:
raise RuntimeError("Invalid input was accepted")
print(per_worker(12, 3))
The assertions demonstrate the good result; the function’s validation does not depend on them. The worker checks were also exercised under optimized mode. This example assumes a numeric total; production validation should match the actual input and failure policy.
Verify the fix, not just the disappearance of the error
- Reproduce the failure in a safe test with the same relevant input shape.
- Inspect the innermost relevant application frame, then follow the data back to its source.
- Correct the cause and add a test for the failing input.
- Test valid input, empty or missing input, and boundary values so the fix does not hide another error.
- Confirm that a scheduled job or web application reports failure appropriately and does not expose internal details publicly.
Verification: The displayed traceback was captured from the exact seven-line script. Tests checked its three frame locations, exception chaining, explicit logging and re-raising, and validation both normally and with -O. No customer logs or production inputs were used.
References: Python errors and exceptions, exception logging and assert behavior. Related: indentation troubleshooting.
Related guides
How to Deploy a FastAPI App with Gunicorn and Nginx
Deploy FastAPI behind Nginx with Gunicorn and systemd. Separate application packages, check HTTPS and verify worker replacement and application health.
PythonLearn How to Modify Python Dictionary Values Easily
Learn how to modify Python dictionary values effectively with various methods, including direct assignment, update(), and comprehensions, along with common mistakes to...
PythonPython Set Copy Tutorial: Avoid Common Mistakes and Data Errors
Learn how to copy sets in Python safely and efficiently while avoiding common mistakes. Explore methods like copy(), set(), and deepcopy().
PythonDifferent Methods to Loop Through Sets in Python (Beginner-Friendly Guide)
Learn diverse methods to loop through sets in Python, including practical examples and use cases, ideal for beginners looking to master set operations.
