bateau84/skills

python-error-handling

Idiomatic exception handling in Python — catching narrowly, custom exception hierarchies, exception chaining with raise ...

Zobacz źródło

Jak używać

  1. Skopiuj polecenie instalacji i sprawdź źródła przed instalacją we własnym środowisku agenta.
  2. W oryginale sprawdź wymagane narzędzia, dane dostępowe i obsługiwane środowiska.
  3. Opisz dane wejściowe i oczekiwany rezultat; porównaj wynik ze źródłami.
npx skills add https://github.com/bateau84/skills --skill python-error-handling

Przed rozpoczęciem

  • Instalacja nie obejmuje subskrypcji modelu, limitu API ani uprawnień do plików.
  • Gwiazdki i instalacje pokazują aktywność, a nie niezależny test jakości lub bezpieczeństwa.
Oryginalny dokument Skill

Treść z repozytorium z zachowaniem nagłówków, przykładów, kodu, tabel, linków i obrazów.

Pair with python-common-practice, python-fastapi (HTTP mapping), python-async (CancelledError), and python-observability (logging errors) as relevant.

Persona: You are a Python engineer who treats exceptions as part of the API. You catch what you can handle and let the rest propagate to someone who can.

Error Handling

Python prefers EAFP ("easier to ask forgiveness than permission") — try the operation and handle the exception rather than pre-checking. Pre-checks race with reality; the exception is the truth.

python
# ✓ EAFP — one atomic attempt
try:
    return cache[key]
except KeyError:
    return load(key)

# ✗ LBYL — racy for I/O; fine when a simple guard avoids broad catching
if key in cache:
    return cache[key]

EAFP is a convention, not a universal rule. Broad catches can hide failures from both humans and agents. Prefer EAFP where the exception type is known and the catch is narrow; inspect the framework's actual error behavior rather than guessing at its hierarchy. Use explicit checks where they express the contract more clearly, while accounting for race conditions between checking and acting.

Catch narrowly

Catch the specific exception you can handle. A bare except: or except Exception: swallows bugs, KeyboardInterrupt, and (in async) cancellation — turning a crash you'd fix into silent wrong behavior.

python
# ✗ Bad — hides programming errors and makes debugging impossible
try:
    sync_playlist(p)
except Exception:
    pass

# ✓ Good — handle the failures you expect; let the rest surface
try:
    sync_playlist(p)
except (httpx.HTTPError, TimeoutError) as e:
    log.warning("sync failed for %s: %s", p.id, e)
    metrics.errors_total.inc()

If you must catch broadly (a top-level worker loop that must not die), log with log.exception(...) to capture the traceback, then continue or re-raise — never pass.

Agent navigability — narrow exception surfaces

Prefer narrow exception surfaces: agents catching from broad hierarchies must guess error object shapes — a predictable interface failure, not a model failure.

Framework guidance — catch the specific exception, not the family:

FrameworkBroad (avoid)Narrow (prefer)
requests / httpxrequests.exceptions.RequestExceptionhttpx.TimeoutException, httpx.HTTPStatusError
django ORMdjango.core.exceptions.ObjectDoesNotExistMyModel.DoesNotExist
SQLAlchemysqlalchemy.exc.SQLAlchemyErrorsqlalchemy.exc.IntegrityError, sqlalchemy.exc.OperationalError

Wrap framework exceptions at the boundary into domain exceptions. This collapses the broad hierarchy into a predictable, narrow surface for all downstream code.

Custom exceptions — a hierarchy with a common base

Give your package one base exception; specific errors subclass it. Callers can then catch the whole family or a specific case. This is what lets a FastAPI handler map all your domain errors in one place.

python
class SortarrError(Exception):
    """Base for all sortarr domain errors."""

class AuthRequiredError(SortarrError): ...
class QuotaExceededError(SortarrError): ...

Subclass the most specific stdlib type when it fits (ValueError, LookupError); invent a new hierarchy only for domain concepts the stdlib doesn't model.

Chain exceptions — preserve the cause

When you wrap a low-level error in a domain one, use raise ... from so the original traceback survives. Bare raise NewError(...) inside an except hides the root cause.

python
try:
    resp = await client.get(url)
    resp.raise_for_status()
except httpx.HTTPStatusError as e:
    raise QuotaExceededError("YouTube quota hit") from e   # ✓ keeps the cause

To deliberately suppress the context, use from None — and only when the cause is genuinely noise.

This is also how you keep storage details out of the API: the repository catches the driver error and raises a domain error, so the route never imports sqlite3 or sees a driver exception.

python
import sqlite3

def save_rule(self, rule: Rule) -> None:
    try:
        self._con.execute("INSERT INTO rules (id, pattern) VALUES (?, ?)", (rule.id, rule.pattern))
    except sqlite3.IntegrityError as e:
        raise DuplicateRuleError(rule.id) from e   # domain error — a handler maps it to 409

else and finally

else runs only when try didn't raise — put success logic there. finally always runs; prefer a context manager over manual try/finally.

python
with open_connection(db_path) as conn:   # closed on any exit path
    conn.execute(...)

Write your own with contextlib.contextmanager or __enter__/__exit__; use async with for async resources.

Re-raise, don't return error sentinels

Returning None/-1/False to signal failure forces every caller to remember to check, and the type checker can't help. Raise instead — the failure can't be silently ignored. (Return X | None only when "not found" is a normal, expected outcome, not an error.)

In async code, never swallow `asyncio.CancelledError` — re-raise it so shutdown and timeouts work (→ See python-async).

Mapping to HTTP

In FastAPI, register one exception handler per domain base class rather than try/except in every route (→ See python-fastapi):

python
@app.exception_handler(AuthRequiredError)
async def _auth(_: Request, exc: AuthRequiredError):
    return JSONResponse(status_code=401, content={"detail": str(exc)})

Never leak a stack trace or internal message to a client — log the detail server-side, return a clean message.

Common mistakes

MistakeFix
except Exception: passCatch the specific type; if broad, log.exception then re-raise.
Bare raise FooError() inside exceptraise FooError() from err to preserve the cause.
except: (bare)Catches KeyboardInterrupt/SystemExit/cancellation too — name the type.
Manual try/finally for cleanupUse a context manager (with).
Returning None/-1 for errorsRaise an exception; reserve None for expected absence.
Swallowing CancelledError in asyncRe-raise it.
Leaking tracebacks to API clientsLog server-side; return a sanitized message.
EAFP with broad except on a framework hierarchyPrefer LBYL guard or narrow catch; wrap at the boundary into a domain exception.

Diagnose: 1- ruff check (bugbear B) — flags overly broad except and raise without from 2- read the full traceback (don't truncate) — the chained from cause usually names the real failure.

References

Powiązane zadania

z tego samego repozytorium

Więcej Skills

Wszystkie Skills
bateau84
Społeczność

behavioral-spec

Derive bounded, implementation-independent requirements from agreed product intent through goal refinement, coverage lenses, obstacle analysis, provenance tracking, and counterexample checks. Use to select, author, and reconcile Behavioral Requirements (BR), Quality Scenarios (QS), and Obligation Contracts (OC) without expanding scope. Not for concrete API/schema/protocol realization (use architectural-spec) or human-centered stories and scenarios (use user-stories-and-scenarios).

Instalacje / 1h
1
GitHub Stars
0
Aktualizacja
18 paź
bateau84
Społeczność

desktop-ui-design

Desktop GUI design for native and hybrid applications: platform conventions (macOS HIG, Windows Fluent, GNOME HIG), menus, keyboard shortcuts, window management, session persistence, native vs Electron/Tauri trade-offs, and accessibility APIs. Use for Swift/AppKit, C/WinUI, GTK+, or Electron/Tauri/Flutter desktop design. Add web-ui-design for a web app shipped as a desktop wrapper. Not for browser-only interfaces, terminal applications (use tui-design), or command-line tools (use cli-design).

Instalacje / 1h
1
GitHub Stars
0
Aktualizacja
18 paź
bateau84
Społeczność

git-commit-discipline

Small coherent commits, explanatory messages, shared-working-tree discipline, and safe undo/recovery. Use when asked to commit, when a diff mixes concerns, when agents share a working tree, or when undoing or recovering Git changes. Not for content conflicts (use git-conflicts).

Instalacje / 1h
1
GitHub Stars
0
Aktualizacja
18 paź
bateau84
Społeczność

golang-dependency-injection

google/wire, uber-go/dig, uber-go/fx, samber/do, manual constructor injection, and service containers in Go. Use when designing service architecture, setting up dependency injection, refactoring tightly coupled code, or managing singletons and service factories.

Instalacje / 1h
1
GitHub Stars
0
Aktualizacja
18 paź