Python
Programming Best Practices
Error Handling
Code Quality
Software Development

Why is except pass a bad programming practice?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

except: pass suppresses all exceptions without logging, recovery, or signaling failure. It hides real defects, corrupts control flow, and makes debugging expensive. While it may seem convenient during prototyping, it is dangerous in production code.

This article explains safer alternatives and when suppression is acceptable.

Core Sections

1) Why bare suppression is harmful

python
1try:
2    process_order(order)
3except:
4    pass

This catches everything, including unexpected bugs like TypeError, and silently continues.

2) Catch specific exceptions

python
1try:
2    value = int(raw)
3except ValueError:
4    value = 0

Specific exceptions communicate intent and preserve unexpected failures.

3) Log before fallback

python
1import logging
2
3try:
4    write_to_remote(payload)
5except TimeoutError as exc:
6    logging.warning("remote write timed out: %s", exc)
7    queue_for_retry(payload)

At minimum, capture context for diagnosis.

4) Use except Exception carefully

If broad catch is required at a boundary, log and re-raise or convert to domain error.

python
1try:
2    run_job()
3except Exception as exc:
4    logger.exception("job failed")
5    raise

Avoid swallowing critical failures.

5) Rare valid suppression cases

Suppress only when failure is explicitly non-critical and documented.

python
1from contextlib import suppress
2
3with suppress(FileNotFoundError):
4    os.remove(tmp_file)

This is safer and self-documenting compared with bare except: pass.

6) Production checklist for Python exception handling

Code examples are necessary, but production readiness depends on how this pattern behaves under failure, load, and operational drift. Before rollout, define success criteria that are measurable. A useful baseline is three metrics: correctness (for example, expected output match rate), reliability (error rate and retry behavior), and latency (p95 or p99 execution time). Capture these metrics in a repeatable test environment rather than relying on ad hoc local runs. If external systems are involved, include at least one synthetic fault scenario such as timeout, malformed payload, or temporary dependency outage. This confirms the implementation fails predictably and recovers in a controlled way.

Document environment assumptions close to the code. Include runtime version constraints, required environment variables, and exact dependency versions used during validation. Many regressions come from mismatched environments rather than algorithmic changes. A short README snippet or inline comment that names these assumptions can prevent repeated troubleshooting later. Also define ownership for operational issues: who receives alerts, what threshold triggers action, and what rollback path is acceptable. Without explicit ownership and rollback criteria, otherwise small incidents can take longer to resolve.

A practical rollout sequence is:

  1. Run automated checks (lint, unit tests, static validation) in CI.
  2. Execute a smoke test against representative input sizes.
  3. Validate one failure mode and verify error visibility in logs.
  4. Deploy behind a feature flag or phased rollout if possible.
  5. Monitor key metrics for a defined stabilization window.
bash
1# Example operator workflow
2make lint
3make test
4./scripts/smoke_check.sh

Finally, keep a short limitations section. State what the current approach intentionally does not optimize or support. This prevents accidental misuse by future contributors and keeps design discussions grounded in explicit tradeoffs. For long-lived systems, schedule periodic review of this implementation, especially after runtime upgrades or library changes. A lightweight maintenance cadence often catches compatibility issues before they become production incidents.

Common Pitfalls

  • Catching all exceptions and masking real bugs.
  • Losing stack traces and error context needed for incident response.
  • Continuing execution with partially updated state.
  • Using suppression instead of fixing known failure modes.
  • Applying blanket try/except blocks around large code regions.

Summary

except: pass is generally a code smell because it trades short-term convenience for long-term instability. Prefer specific exception handling, logging, and explicit recovery paths. Suppress only narrowly and intentionally.

A short maintenance note should accompany this implementation in your repository docs so future contributors know expected behavior, validation steps, and rollback options. That small documentation investment usually prevents repeat regressions during dependency upgrades, framework changes, and environment migrations.


Course illustration
Course illustration

All Rights Reserved.