16  Errors and Exceptions

16.1 The Wall

AI wrapped everything in try: ... except: pass and your errors vanished. The program did not crash anymore, but it also did not work. It silently swallowed every problem. You had no idea where things went wrong because the error messages were being hidden.

Or the opposite: AI did not add error handling at all, and the program crashed on the first unexpected input with a traceback you could not read.

This chapter fixes that.

16.2 Thinking Session

16.2.1 Getting Oriented

NoteThinking Session Prompt

What is the difference between a syntax error and an exception in Python? When I see a traceback, what information does it give me? Walk me through how to read a Python error message. I want to be able to look at AI-generated tracebacks and immediately find the problem.

Your AI should explain: syntax errors are caught before the code runs (missing colons, bad indentation), exceptions happen during execution (dividing by zero, missing keys, wrong types). The traceback reads bottom-up: the last line is the error, the lines above show the call stack. The file name and line number tell you exactly where to look.

16.2.2 Go Deeper

NoteThinking Session Prompt

What are the most common Python exceptions? I see TypeError, ValueError, KeyError, IndexError, FileNotFoundError, and AttributeError in AI-generated code. For each one, tell me what causes it and show me a one-line example that triggers it.

TipWhat to Look For

TypeError: wrong type for an operation ("5" + 3). ValueError: right type but wrong value (int("hello")). KeyError: missing dictionary key (d["missing"]). IndexError: list index out of range ([1,2][5]). FileNotFoundError: file does not exist. AttributeError: calling a method that does not exist on that type.

NoteThinking Session Prompt

Explain Python’s try/except properly. What is the right way to use it? Why is except: or except Exception: without specifying the error type considered bad practice? What is the finally clause for?

16.2.3 Challenge It

NoteThinking Session Prompt

What is wrong with this error handling?

try:
    data = json.load(open("config.json"))
    result = data["setting"] / data["count"]
    save_to_database(result)
except:
    pass
TipWhat to Look For

Three problems: (1) bare except: catches everything including KeyboardInterrupt and SystemExit. (2) pass silently swallows errors. You will never know something went wrong. (3) the try block is too broad. It should be separate try/excepts for file reading, data access, and database saving. AI generates this pattern constantly.

16.2.4 What You Should Have Learned

  • Syntax errors vs exceptions, different causes, different fixes
  • How to read a traceback: bottom-up, file + line number
  • The common exceptions: TypeError, ValueError, KeyError, IndexError
  • try/except should catch specific exceptions, not bare except
  • Never use except: pass, at minimum, log the error
  • finally runs whether or not an exception occurred

16.3 The Gap

You can now read Python error messages and understand what went wrong. When AI generates error handling, you can evaluate whether it is catching the right exceptions or blindly swallowing everything. This is a critical skill, bad error handling is worse than no error handling.

In the Building Session, you will add proper error handling to your chatbot.

16.4 Building Session

16.4.1 The Spec

Add robust error handling to your chatbot:

  • Handle FileNotFoundError when loading conversation history
  • Handle json.JSONDecodeError when the history file is corrupted
  • Handle KeyboardInterrupt (Ctrl+C) gracefully
  • Log errors instead of silently ignoring them

16.4.2 Prompt It

NoteBuilding Session Prompt

Update my chatbot to v1.6. Add proper error handling:

  • Wrap the history file loading in try/except that handles FileNotFoundError and json.JSONDecodeError separately, with specific error messages for each
  • Add a try/except around the main loop that catches KeyboardInterrupt and saves history before exiting
  • Add an error_log list that stores error messages during the session
  • Add an “errors” command that shows any errors that occurred
  • Never use bare except: or except: pass

Keep existing features.

16.4.3 Read the Code

Your AI will produce something like this:

def load_history():
    """Load history with specific error handling."""
    try:
        with open(HISTORY_FILE, "r") as f:
            return json.load(f)
    except FileNotFoundError:
        print(f"{BOT_NAME}: No previous history found. "
              "Starting fresh.")
        return []
    except json.JSONDecodeError:
        print(f"{BOT_NAME}: History file corrupted. "
              "Starting fresh.")
        return []


def main():
    """Main loop with error handling."""
    display_welcome(BOT_NAME, VERSION)
    user_name = get_user_name(BOT_NAME)
    history = load_history()
    error_log = []

    try:
        while True:
            user_input = input(f"{user_name}: ").strip()
            if not user_input:
                continue
            # ... response logic ...
    except KeyboardInterrupt:
        print(f"\n{BOT_NAME}: Interrupted! Saving...")
    finally:
        save_history(history)
        print(f"{BOT_NAME}: History saved. Goodbye!")
TipWhat to Notice

Each except catches a specific exception with a helpful message. KeyboardInterrupt is caught separately. It is not a bug, it is a user action. The finally block saves history regardless of how the loop ends (quit command, Ctrl+C, or unexpected error). Errors are logged to a list, not silently discarded.

16.4.4 Stretch It

NoteBuilding Session Prompt

Add a custom exception class ChatbotError that is raised when the chatbot encounters an invalid command format. Catch it in the main loop and add the error to the error_log.

16.5 Your Chatbot So Far

  • Ch 1-14: Full features with dictionaries and string processing
  • Ch 15: File persistence
  • Ch 16: Proper error handling, error logging, graceful shutdown

16.6 Quick Reference

# Specific exception handling
try:
    result = int(user_input)
except ValueError:
    print("Not a valid number")
except TypeError:
    print("Wrong type")

# Multiple exceptions
except (ValueError, TypeError) as e:
    print(f"Error: {e}")

# finally always runs
try:
    f = open("file.txt")
except FileNotFoundError:
    print("Missing file")
finally:
    print("This always runs")

# Raise your own
raise ValueError("Invalid input")

# Custom exception
class ChatbotError(Exception):
    pass