go-error-handler

Analyze Go error handling patterns — detect swallowed errors, missing error wrapping, sentinel vs custom error usage, type assertions, and idiomatic error propagation. Use when reviewing Go codebases for error handling quality or enforcing Go error conventions.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "go-error-handler" with this command: npx skills add charlie-morrison/go-error-handler

Go Error Handler Analyzer

Deep analysis of error handling patterns in Go codebases. Detects swallowed errors, missing wrapping context, incorrect sentinel usage, unsafe type assertions, and non-idiomatic patterns. Produces prioritized findings aligned with Go proverbs and stdlib conventions.

Use when: reviewing Go code for production readiness, auditing error handling, or establishing team conventions.

Analysis Steps

1. Project Discovery

cat go.mod 2>/dev/null | head -10
find . -name "*.go" -not -path '*/vendor/*' | wc -l
find . -type d -name "errors" -o -name "errs" -not -path '*/vendor/*' 2>/dev/null
grep "pkg/errors\|go.uber.org/multierr\|cockroachdb/errors" go.mod 2>/dev/null

Determine: Go version (affects errors.Is/As availability), error library usage, custom error infrastructure.

2. Swallowed Errors

Most critical check. A swallowed error is an err return value that is ignored.

# Explicit underscore ignoring error
grep -rn '\b_\s*=.*(' --include="*.go" . 2>/dev/null | grep -v 'vendor/\|_test.go' | head -25

# err assigned but never checked
grep -rn 'err\s*=' --include="*.go" . 2>/dev/null | grep -v 'if.*err\|return.*err\|vendor/' | head -20

# defer with ignored error (defer f.Close())
grep -rn 'defer.*Close()\|defer.*Flush()\|defer.*Rollback()' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -15

# http.Error without return (handler continues after error response)
grep -A2 'http\.Error(' --include="*.go" . 2>/dev/null | grep -v 'return\|vendor/' | head -15

Severity guide:

  • Critical: ignored errors from DB, file I/O, network calls
  • High: _ = someFunc() on functions that can fail meaningfully
  • Medium: defer f.Close() without error handling — use named return + defer closure
  • Low: ignoring fmt.Fprintf to stdout (acceptable in CLIs)

3. Error Wrapping Analysis

# Proper wrapping with %w (Go 1.13+)
grep -rn 'fmt\.Errorf.*%w' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -15

# %v/%s instead of %w (loses error chain)
grep -rn 'fmt\.Errorf.*%[vs].*err\b' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -15

# Bare return of error without wrapping (loses context)
grep -rn 'return.*err$' --include="*.go" . 2>/dev/null | grep -v 'nil\|vendor/\|_test.go' | head -20

# Error message conventions (should not start with capital or end with punctuation)
grep -rn 'fmt\.Errorf("[ ]*[A-Z]' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10
grep -rn 'errors\.New(".*\.")' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10

Flag:

  • %v instead of %w: fmt.Errorf("failed: %v", err) breaks errors.Is()/errors.As() — use %w
  • Bare error return: return err across package boundaries loses call-site context — wrap with fmt.Errorf("operation: %w", err)
  • Capitalized/punctuated error messages: Go convention is lowercase, no trailing period (errors compose)

4. Sentinel & Custom Error Patterns

# Sentinel errors
grep -rn 'var\s\+Err[A-Z].*=\s*errors\.New' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -15

# String comparison instead of errors.Is (fragile)
grep -rn 'err\.Error()\s*==' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10

# Direct equality (breaks with wrapping)
grep -rn 'err\s*==\s*Err\|err\s*!=\s*Err' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10

# errors.Is / errors.As usage (correct patterns)
grep -rn 'errors\.Is(\|errors\.As(' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -15

# Custom error types
grep -rn 'func.*Error()\s*string' --include="*.go" . 2>/dev/null | grep -v 'vendor/\|_test.go' | head -15

# Type assertion on errors (fragile with wrapping)
grep -rn 'err\.(\*' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10

Flag:

  • String comparison: err.Error() == "not found" — use errors.Is(err, ErrNotFound)
  • Direct equality: err == ErrNotFound fails if wrapped — use errors.Is()
  • Type assertion: err.(*MyError) fails on wrapped errors — use errors.As()
  • Missing Unwrap: custom error types wrapping other errors must implement Unwrap() error
  • Repeated string errors: errors.New("not found") in multiple places should be a sentinel

5. HTTP Handler & Goroutine Errors

# Internal errors leaked to client (security risk)
grep -rn 'http\.Error(w,.*err\.Error()' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10

# Panic in non-test code
grep -rn 'panic(' --include="*.go" . 2>/dev/null | grep -v 'vendor/\|_test.go' | head -10

# Goroutines without error propagation
grep -B2 -A10 'go func()' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -30

# errgroup usage
grep -rn 'errgroup\|g\.Go\|group\.Go' --include="*.go" . 2>/dev/null | grep -v 'vendor/' | head -10

Flag:

  • Internal error leaked: http.Error(w, err.Error(), 500) sends raw errors to clients — log internally, return generic message
  • Missing return after http.Error: handler continues, potentially writing multiple responses
  • Goroutine with no error channel/errgroup: errors silently lost
  • Missing recover in long-running goroutines: panic crashes entire program
  • errgroup without context: use errgroup.WithContext to cancel remaining goroutines on first error

6. Error Test Coverage

grep -rn 'wantErr\|expectErr\|shouldErr' --include="*_test.go" . 2>/dev/null | grep -v 'vendor/' | head -15

# Packages with no error path tests
for pkg in $(find . -name "*.go" -not -name "*_test.go" -not -path '*/vendor/*' | sed 's|/[^/]*$||' | sort -u); do
  if [ -z "$(grep -rl 'wantErr\|shouldErr' ${pkg}/*_test.go 2>/dev/null)" ]; then
    echo "NO_ERROR_TESTS: $pkg"
  fi
done | head -10

Output Template

# Go Error Handling Analysis — [Module Name]

## Summary
- Files: N | Go: 1.XX | Error lib: stdlib/pkg/errors
- Critical: N | Warnings: N | Error test coverage: low/moderate/good

## Critical Findings
### [C1] Swallowed Database Error
- **File**: internal/repo/user.go:45
- **Code**: `rows, _ := db.Query(query, args...)`
- **Fix**: Handle error, return `fmt.Errorf("query users: %w", err)`

### [C2] Internal Error Leaked to Client
- **File**: internal/handler/order.go:78
- **Fix**: Log error, return `http.Error(w, "internal server error", 500)`

## Error Wrapping Issues
| File | Line | Issue | Fix |
|------|------|-------|-----|
| repo/user.go | 23 | `%v` not `%w` | Change to `%w` |
| service/order.go | 45 | Bare `return err` | Add context wrapping |

## Sentinel Error Inventory
| Package | Sentinel | Checked With |
|---------|----------|-------------|
| repo | ErrNotFound | errors.Is (correct) |
| auth | ErrExpired | err == (fix: errors.Is) |

## Recommendations
1. Replace N instances of `_ = operation()` with error handling
2. Change N `%v` to `%w` in fmt.Errorf calls
3. Add wrapping context to N bare `return err` statements
4. Install recovery middleware for HTTP server
5. Add error path tests to N packages

Error Handling Checklist

RuleSeverityGo Proverb
Never ignore errorsCritical"Errors are values"
Wrap with context at boundariesHighEach layer adds context
Use %w not %vHighPreserve error chains
Use errors.Is not ==HighWorks across wrapping
Use errors.As not type assertionHighWorks across wrapping
Return after http.ErrorCriticalPrevent double-write
Don't leak internals to clientsCriticalSecurity boundary
Propagate errors from goroutinesHighSilent failures are worst

Tips

  • Run errcheck ./... to catch unchecked errors mechanically
  • Use golangci-lint with wrapcheck, errcheck, goerr113 linters
  • For multi-error scenarios use errors.Join (Go 1.20+) or go.uber.org/multierr
  • Always handle defer Close() errors for writers — flushed data may fail to write

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

Go Install

Install Go 1.22 compiler on Linux, configure environment variables, and provide commands for development, testing, building, and dependency management.

Registry SourceRecently Updated
3040Profile unavailable
General

Go 安装

在 Linux 系统安装并配置 Go 编译器,支持 Go 项目编译、测试及依赖管理操作。

Registry SourceRecently Updated
3000Profile unavailable
General

Go Production Engineering

Expertise in Go project architecture, error handling, concurrency safety, testing, observability, configuration, CI/CD, and documentation for production depl...

Registry SourceRecently Updated
5020Profile unavailable
Coding

GitHub 人才猎手 (GitHub Talent Hunter)

从 GitHub 找到最匹配的技术人才,生成个性化触达话术。适用于招聘工程师、寻找技术合伙人、猎头交付候选人等场景。

Registry SourceRecently Updated
1500Profile unavailable