L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Design et création · SKILL.md

error-handling

error-handling

Designs what a system does when things go wrong, which errors to catch, what to retry, what to surface, and what to let crash. Use this whenever the user is writing try/except or error branches, adding retries or timeouts, asking how to handle a failure case, or dealing with code that swallows errors silently. Also use when a system fails in confusing ways …

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: error-handling description: Designs what a system does when things go wrong, which errors to catch, what to retry, what to surface, and what to let crash. Use this whenever the user is writing try/except or error branches, adding retries or timeouts, asking how to handle a failure case, or dealing with code that swallows errors silently. Also use when a system fails in confusing ways or logs are useless during an incident. For finding the cause of a specific failure, use debugging. license: MIT

Error handling

Most error handling is written reflexively — wrap it, log it, move on, and that reflex produces systems that fail silently and are impossible to debug. The decision to make for each failure is not how to handle it but whether you can do anything useful about it.

If you cannot, do not catch it. A caught-and-logged exception that leaves the program in a wrong state is worse than a crash, because the crash would have told you immediately.

1. Sort every failure into one of four kinds

KindExampleResponse
ExpectedNot found, validation failed, duplicateReturn it as a value. Not an exception — this is normal operation
TransientTimeout, 503, connection reset, lock contentionRetry with backoff, then give up and report
Programmer errorNull where it cannot be null, broken invariantCrash. Loudly. Do not handle
EnvironmentalConfig missing, disk full, credentials invalidFail at startup if possible, not on first request

The two most common mistakes are treating expected outcomes as exceptions, which makes normal control flow expensive and noisy, and catching programmer errors, which hides the bug and lets corrupted state spread.

Done when: every failure path in the code maps to one of these four.

2. Catch only what you can act on

Catch a specific error type, at the level that knows what to do about it. That level is often much higher than where the error occurs.

  • Never catch broadly: a bare except, catch (Exception), or catch {} also swallows programmer errors, cancellations, and out-of-memory.
  • Never catch and continue with a default unless the default is genuinely correct. Returning an empty list on a database timeout tells the caller "no results", which is a lie that propagates.
  • Never log and rethrow at every level. You get the same error six times in the log with no extra information.

Done when: every catch block does something other than logging.

3. Preserve the cause

When you wrap an error, keep the original attached — raise ... from e, %w, cause:. An error chain that loses its root is the reason incidents take hours instead of minutes.

Add context on the way up: what you were doing, with which identifiers. "Failed to sync order 88213 for tenant acme" is actionable; "sync failed" is not. Add the values you had, never the secrets.

Done when: one log line at the boundary tells you what failed, for which entity, and why.

4. Retry only what is safe and transient

Retries convert a small outage into a large one when applied carelessly.

  • Only retry idempotent operations, or ones with an idempotency key. Retrying a payment because the response timed out can charge twice, the request may well have succeeded.
  • Only retry transient errors. A 400 retried five times is five identical failures.
  • Exponential backoff with jitter. Fixed-interval retries from many clients synchronise and hammer a recovering service — the retry storm is often worse than the original fault.
  • Cap total attempts and total time, and make both visible to the caller.
  • Fail fast when the dependency is down. A circuit breaker beats a queue of doomed retries.

Done when: each retry has a stated reason it is safe.

5. Design what the user sees

Three different audiences need three different things from the same failure:

  • End user: what happened in their terms, and what to do next. No stack trace, no error code alone.
  • Calling system: a stable machine-readable code and whether to retry. See api-design.
  • You, at 3am: the full chain, the identifiers, the request ID that ties it to a trace.

The request ID is the piece that gets forgotten and matters most: it is what lets a user report and a log line meet.

Done when: a user report can be traced to the exact failure without guessing.

6. Fail in a safe state

  • Clean up on the error path too: connections, locks, temp files, partial writes. Use the language's scope-based mechanism rather than manual cleanup in a catch.
  • Decide what partial success means. If three of five items processed, is that success, failure, or a reported partial? Decide deliberately, the default is usually wrong.
  • Never leave a half-applied change. Transaction, compensating action, or an idempotent design that tolerates re-running.

Done when: an error mid-operation leaves nothing inconsistent.

Report

State which failures you handle and which you deliberately let propagate, what is retried and why that is safe, and what a user sees for each. The failures you chose not to handle are the part reviewers most need to see, because silence there reads as an oversight.

Skills enregistrées