The Rule
All exception handlers must have visibility.
# BAD: Silent swallowing
except ValueError:
pass
# GOOD: Minimum DEBUG log
except ValueError as e:
logger.debug("Parse failed, using fallback: %s", e)
Exception Levels
| Level |
When |
Example |
ERROR |
Data loss risk, user action needed |
Database write failed |
WARNING |
Degraded but recoverable |
API retry after timeout |
DEBUG |
Expected fallback paths |
JSON parse → markdown extraction |
Patterns
Database
try:
with DatabaseConnection(db_path, exclusive=True) as conn:
cursor.execute(sql, params)
except sqlite3.IntegrityError as e:
logger.error("Constraint violation: %s", e)
raise
File Operations
try:
with open(config_path) as f:
config = json.load(f)
except FileNotFoundError:
logger.debug("Config not found, using defaults: %s", config_path)
config = DEFAULT_CONFIG
except json.JSONDecodeError as e:
logger.warning("Invalid JSON in %s: %s", config_path, e)
config = DEFAULT_CONFIG
API Retry
for attempt in range(3):
try:
response = api_client.request(data)
break
except TimeoutError:
logger.warning("API timeout (attempt %d/3)", attempt + 1)
if attempt == 2:
logger.error("API failed after 3 retries")
raise
time.sleep(2 ** attempt)
Anti-Patterns
| Pattern |
Problem |
except: pass |
Bug hider |
except Exception: return None |
What failed? Why? |
except Exception as e: return default |
Hides TypeError, AttributeError |
except KeyError: logger.error(...) |
ERROR for expected path (should be DEBUG) |
Domain Exceptions
from formaltask.exceptions import TaskNotFoundError, EpicNotFoundError
from formaltask.tasks.lifecycle import InvalidTransitionError
raise TaskNotFoundError(task_id) # Not TaskNotFoundError("msg")
CLI Errors
from formaltask.cli.base import CLIError
from formaltask.cli.exit_codes import ExitCode
raise CLIError("Task not found", exit_code=ExitCode.NOT_FOUND)
Gotchas
| Problem |
Fix |
| Silent except pass |
Always log at minimum DEBUG |
| Wrong log level |
ERROR = action needed, DEBUG = expected |
| Over-broad catch |
Catch specific exceptions |
| Lost stack trace |
Use raise not raise e |
Converted and distributed by TomeVault — claim your Tome and manage your conversions.