# Error Handling Anti-Patterns
# Patterns that hide errors instead of surfacing them

name: Error Handling
description: |
  Detects patterns where errors are silently swallowed, logged but ignored,
  or hidden behind default return values. These patterns make debugging hard
  and can lead to systems running with corrupted or partial state.

patterns:
  - id: log-and-continue
    description: Logging error then continuing with default/None
    grep_pattern: 'logger\.(warning|error|exception).*\n.*return (None|\[\]|\{\}|0|False)'
    multiline: true
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "Caller cannot detect failure; continues with partial data"
      OK_IF: "Method documents None as valid return; caller handles it"

  - id: catch-log-pass
    description: Exception caught, logged, but silently swallowed
    grep_pattern: 'except.*:\n\s*(pass|logger\.(warning|error))'
    multiline: true
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "Exception swallowed without re-raise or failure indicator"
      OK_IF: "Exception is expected case (e.g., cache miss) with proper handling"

  - id: bare-except
    description: Bare except clause catches everything including SystemExit
    grep_pattern: 'except:\s*$'
    context_lines: 3
    verdict_hints:
      ISSUE_IF: "Catches KeyboardInterrupt, SystemExit - use Exception instead"
      OK_IF: "Never OK - always specify exception type"

  - id: broad-exception-catch
    description: Catching Exception without re-raising
    grep_pattern: 'except Exception.*:\n(?!.*raise)'
    multiline: true
    context_lines: 7
    verdict_hints:
      ISSUE_IF: "Broad catch without re-raise hides unexpected errors"
      OK_IF: "Re-raises as domain exception with context preserved"

  - id: silent-none-return
    description: Returning None/empty on lookup failure without logging
    grep_pattern: 'if .* is None:\n\s*return (None|\[\]|\{\})'
    multiline: true
    context_lines: 4
    verdict_hints:
      ISSUE_IF: "None indicates error condition but no logging/metric"
      OK_IF: "None is valid business case (e.g., optional field not set)"

  - id: continue-on-error
    description: Loop continues past errors without tracking failures
    grep_pattern: 'except.*:\n.*continue'
    multiline: true
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "Errors silently skipped; loop completes with partial results"
      OK_IF: "Failures tracked and reported after loop; caller informed"

  - id: default-on-keyerror
    description: Using .get() with default to hide missing keys
    grep_pattern: '\.get\([^,]+,\s*(None|\[\]|\{\}|0|"")\)'
    context_lines: 2
    verdict_hints:
      ISSUE_IF: "Missing key indicates data corruption; should raise"
      OK_IF: "Key genuinely optional with documented default behavior"

  - id: suppress-validation-error
    description: Catching validation errors without surfacing to user
    grep_pattern: 'except.*(ValidationError|ValueError|TypeError).*:\n.*return'
    multiline: true
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "User provided bad input but gets generic response"
      OK_IF: "Error converted to proper HTTP 400/422 with details"
