Clean code error handling
Skill lifeodyssey/craftsmanship-skills/skills/clean-code-error-handling
Agent Skills distilled from Clean Code & Refactoring. Install: npx skills add lifeodyssey/craftsmanship-skills
npx -y skills add lifeodyssey/craftsmanship-skills --skill clean-code-error-handlingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when designing or reviewing exception handling, error boundaries, or error propagation patterns — applies Clean Code error handling principles
SKILL.md
3.0 KB, as published. Nobody here has run it
Clean Code: Error Handling
Based on Robert C. Martin's Clean Code, Chapter 7: Error Handling.
When to Use This Skill
Trigger on:
- Designing exception handling strategy
- Reviewing try/catch blocks
- Debates about exceptions vs. error codes
- Error propagation across layers/boundaries
Rules
1. Use Exceptions Rather Than Return Codes
Return codes require the caller to check immediately. Exceptions bubble up naturally.
# Bad — caller must check return code
result = transfer(from_acct, to_acct, amount)
if result == ERROR_INSUFFICIENT_FUNDS:
handle_error()
elif result == ERROR_INVALID_ACCOUNT:
handle_other_error()
# Good — exception bubbles up naturally
try:
transfer(from_acct, to_acct, amount)
except InsufficientFundsError:
handle_error()
except InvalidAccountError:
handle_other_error()
2. Write Try/Catch First
Structure your error handling before writing the happy path. It forces you to think about what can go wrong.
3. Use Unchecked Exceptions
Checked exceptions break encapsulation. Every callee must know about every exception thrown below it.
4. Provide Context with Exceptions
Always include enough context to determine the source and location of an error.
# Bad
raise ValueError("Invalid")
# Good
raise PaymentProcessingError(
f"Failed to process payment for order {order_id}: "
f"insufficient funds (balance={balance}, required={amount})"
)
5. Define Exception Classes in Terms of Caller's Needs
Group by how you want to handle them, not by where they originate.
# Good — grouped by caller's handling needs
class PaymentError(Exception): pass
class InsufficientFunds(PaymentError): pass
class AccountFrozen(PaymentError): pass
class NetworkTimeout(PaymentError): pass
6. Define the Normal Flow
Use the Special Case pattern instead of exception handling for expected conditions.
# Bad — exception for expected case
try:
total = calculate_total(customer)
except NoActiveSubscription:
total = 0
# Good — Special Case pattern
class NullCustomer:
def calculate_total(self):
return 0
7. Don't Return Null
Returning null forces null checks everywhere. Return a null object or empty collection instead.
8. Don't Pass Null
Passing null into functions is asking for trouble. If a function cannot accept null, assert it early.
Quick Checklist
- Are exceptions used instead of return codes?
- Does each exception include enough context?
- Are exception classes organized by handler needs?
- Is there a Special Case pattern for expected "errors"?
- Are nulls avoided (return empty collections/objects instead)?
- Does every try block have a clear catch?
Source
Distilled from Clean Code by Robert C. Martin, Chapter 7: Error Handling.