# ERROR: tearDown (tests.test_foo.TestFoo) ...
Traceback (most recent call last):
  File "...", line N, in tearDown
    self.conn.close()
AttributeError: 'NoneType' object has no attribute 'close'

- **ID:** `python/unittest-teardown-exception-masks-test`
- **Domain:** python
- **Category:** runtime_error
- **Verification:** ai_generated
- **Fix Rate:** 80%

## Root Cause

tearDown references an attribute that setUp failed to assign (e.g., because setUp raised or was skipped), so the cleanup runs against an uninitialized value.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| 3.11 | active | — | — |
| 3.12 | active | — | — |

## Workarounds

1. **** (94% success)
   ```
   def tearDown(self):
    conn = getattr(self, 'conn', None)
    if conn is not None:
        conn.close()
    super().tearDown()
   ```
2. **** (96% success)
   ```
   def setUp(self):
    self.conn = connect()
    self.addCleanup(self.conn.close)

# addCleanup runs only if the resource was created
   ```

## Dead Ends

- **** — Silences the error but leaks resources (open sockets, temp files) and hides genuine teardown bugs, causing cascading failures in later tests. (70% fail)
- **** — addCleanup still calls the same code path; if the attribute is None the same AttributeError is raised, now reported as a cleanup error. (80% fail)
