{"id":"3a74c0ef-8d5e-48ba-bef2-0929a19eb30a","shortId":"tqJTHJ","kind":"skill","title":"golang-error-handling","tagline":"Idiomatic Golang error handling — creation, wrapping with %w, errors.Is/As, errors.Join, custom error types, sentinel errors, panic/recover, the single handling rule, structured logging with slog, HTTP request logging middleware, and samber/oops for production errors. Built to ma","description":"**Persona:** You are a Go reliability engineer. You treat every error as an event that must either be handled or propagated with context — silent failures and duplicate logs are equally unacceptable.\n\n**Modes:**\n\n- **Coding mode** — writing new error handling code. Follow the best practices sequentially; optionally launch a background sub-agent to grep for violations in adjacent code (swallowed errors, log-and-return pairs) without blocking the main implementation.\n- **Review mode** — reviewing a PR's error handling changes. Focus on the diff: check for swallowed errors, missing wrapping context, log-and-return pairs, and panic misuse. Sequential.\n- **Audit mode** — auditing existing error handling across a codebase. Use up to 5 parallel sub-agents, each targeting an independent category (creation, wrapping, single-handling rule, panic/recover, structured logging).\n\n> **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-error-handling` skill takes precedence.\n\n# Go Error Handling Best Practices\n\nThis skill guides the creation of robust, idiomatic error handling in Go applications. Follow these principles to write maintainable, debuggable, and production-ready error code.\n\n## Best Practices Summary\n\n1. **Returned errors MUST always be checked** — NEVER discard with `_`\n2. **Errors MUST be wrapped with context** using `fmt.Errorf(\"{context}: %w\", err)`\n3. **Error strings MUST be lowercase**, without trailing punctuation\n4. **Use `%w` internally, `%v` at system boundaries** to control error chain exposure\n5. **MUST use `errors.Is` and `errors.As`** instead of direct comparison or type assertion\n6. **SHOULD use `errors.Join`** (Go 1.20+) to combine independent errors\n7. **Errors MUST be either logged OR returned**, NEVER both (single handling rule)\n8. **Use sentinel errors** for expected conditions, custom types for carrying data\n9. **NEVER use `panic` for expected error conditions** — reserve for truly unrecoverable states\n10. **SHOULD use `slog`** (Go 1.21+) for structured error logging — not `fmt.Println` or `log.Printf`\n11. **Use `samber/oops`** for production errors needing stack traces, user/tenant context, or structured attributes\n12. **Log HTTP requests** with structured middleware capturing method, path, status, and duration\n13. **Use log levels** to indicate error severity\n14. **Never expose technical errors to users** — translate internal errors to user-friendly messages, log technical details separately\n15. **Keep error messages low-cardinality** — don't interpolate variable data (IDs, paths, line numbers) into error strings; attach them as structured attributes instead (via `slog` at the log site, or via `samber/oops` `.With()` on the error itself) so APM/log aggregators (Datadog, Loki, Sentry) can group errors properly\n\n## Detailed Reference\n\n- **[Error Creation](./references/error-creation.md)** — How to create errors that tell the story: error messages should be lowercase, no punctuation, and describe what happened without prescribing action. Covers sentinel errors (one-time preallocation for performance), custom error types (for carrying rich context), and the decision table for which to use when.\n\n- **[Error Wrapping and Inspection](./references/error-wrapping.md)** — Why `fmt.Errorf(\"{context}: %w\", err)` beats `fmt.Errorf(\"{context}: %v\", err)` (chains vs concatenation). How to inspect chains with `errors.Is`/`errors.As` for type-safe error handling, and `errors.Join` for combining independent errors.\n\n- **[Error Handling Patterns and Logging](./references/error-handling.md)** — The single handling rule: errors are either logged OR returned, NEVER both (prevents duplicate logs cluttering aggregators). Panic/recover design, `samber/oops` for production errors, and `slog` structured logging integration for APM tools.\n\n## Parallelizing Error Handling Audits\n\nWhen auditing error handling across a large codebase, use up to 5 parallel sub-agents (via the Agent tool) — each targets an independent error category:\n\n- Sub-agent 1: Error creation — validate `errors.New`/`fmt.Errorf` usage, low-cardinality messages, custom types\n- Sub-agent 2: Error wrapping — audit `%w` vs `%v`, verify `errors.Is`/`errors.As` patterns\n- Sub-agent 3: Single handling rule — find log-and-return violations, swallowed errors, discarded errors (`_`)\n- Sub-agent 4: Panic/recover — audit `panic` usage, verify recovery at goroutine boundaries\n- Sub-agent 5: Structured logging — verify `slog` usage at error sites, check for PII in error messages\n\n## Cross-References\n\n- → See `samber/cc-skills-golang@golang-samber-oops` for full samber/oops API, builder patterns, and logger integration\n- → See `samber/cc-skills-golang@golang-observability` for structured logging setup, log levels, and request logging middleware\n- → See `samber/cc-skills-golang@golang-safety` for nil interface trap and nil error comparison pitfalls\n- → See `samber/cc-skills-golang@golang-naming` for error naming conventions (ErrNotFound, PathError)\n- → See `samber/cc-skills-golang@golang-continuous-integration` skill for automated AI-driven code review in CI using these guidelines\n\n## References\n\n- [lmittmann/tint](https://github.com/lmittmann/tint)\n- [samber/oops](https://github.com/samber/oops)\n- [samber/slog-multi](https://github.com/samber/slog-multi)\n- [samber/slog-sampling](https://github.com/samber/slog-sampling)\n- [samber/slog-formatter](https://github.com/samber/slog-formatter)\n- [samber/slog-http](https://github.com/samber/slog-http)\n- [samber/slog-sentry](https://github.com/samber/slog-sentry)\n- [log/slog package](https://pkg.go.dev/log/slog)","tags":["golang","error","handling","skills","samber","agent","agent-skills","antigravity","claude","claude-code","code","codex"],"capabilities":["skill","source-samber","skill-golang-error-handling","topic-agent","topic-agent-skills","topic-antigravity","topic-claude","topic-claude-code","topic-code","topic-codex","topic-coding","topic-copilot","topic-cursor","topic-gemini","topic-gemini-cli-extension"],"categories":["cc-skills-golang"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/samber/cc-skills-golang/golang-error-handling","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add samber/cc-skills-golang","source_repo":"https://github.com/samber/cc-skills-golang","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 1725 github stars · SKILL.md body (5,646 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:53:01.061Z","embedding":null,"createdAt":"2026-04-18T20:31:30.046Z","updatedAt":"2026-05-18T18:53:01.061Z","lastSeenAt":"2026-05-18T18:53:01.061Z","tsv":"'/as,':15 '/lmittmann/tint)':760 '/log/slog)':789 '/references/error-creation.md':449 '/references/error-handling.md':539 '/references/error-wrapping.md':501 '/samber/oops)':764 '/samber/slog-formatter)':776 '/samber/slog-http)':780 '/samber/slog-multi)':768 '/samber/slog-sampling)':772 '/samber/slog-sentry)':784 '1':223,604 '1.20':285 '1.21':333 '10':328 '11':342 '12':356 '13':369 '14':377 '15':396 '2':233,620 '3':245,634 '4':254,651 '5':154,267,586,664 '6':280 '7':290 '8':303 '9':315 'across':148,579 'action':471 'adjac':99 'agent':93,158,590,593,603,619,633,650,663 'aggreg':437,556 'ai':747 'ai-driven':746 'alway':227 'api':691 'apm':569 'apm/log':436 'applic':206 'assert':279 'attach':415 'attribut':355,419 'audit':142,144,574,576,623,653 'autom':745 'background':90 'beat':507 'best':84,192,220 'block':109 'boundari':261,660 'builder':692 'built':40 'captur':363 'cardin':402,613 'carri':313,485 'categori':163,600 'chain':265,512,518 'chang':121 'check':126,229,673 'ci':752 'clutter':555 'code':75,81,100,219,749 'codebas':150,582 'combin':287,531 'communiti':173 'compani':176 'comparison':276,724 'concaten':514 'condit':309,322 'context':65,132,239,242,352,487,504,509 'continu':741 'control':263 'convent':734 'cover':472 'creat':452 'creation':9,164,198,448,606 'cross':680 'cross-refer':679 'custom':17,310,481,615 'data':314,407 'datadog':438 'debugg':213 'decis':490 'default':174 'describ':466 'design':558 'detail':394,445 'diff':125 'direct':275 'discard':231,646 'driven':748 'duplic':69,553 'durat':368 'either':59,294,546 'engin':49 'equal':72 'err':244,506,511 'errnotfound':735 'error':3,7,18,21,39,53,79,102,119,129,146,184,190,202,218,225,234,246,264,289,291,306,321,336,347,375,381,386,398,413,433,443,447,453,458,474,482,497,526,533,534,544,562,572,577,599,605,621,645,647,671,677,723,732 'errors.as':272,521,629 'errors.is':14,270,520,628 'errors.is/as,':13 'errors.join':16,283,529 'errors.new':608 'event':56 'everi':52 'exist':145 'expect':308,320 'explicit':179 'expos':379 'exposur':266 'failur':67 'find':638 'fmt.errorf':241,503,508,609 'fmt.println':339 'focus':122 'follow':82,207 'friend':390 'full':689 'github.com':759,763,767,771,775,779,783 'github.com/lmittmann/tint)':758 'github.com/samber/oops)':762 'github.com/samber/slog-formatter)':774 'github.com/samber/slog-http)':778 'github.com/samber/slog-multi)':766 'github.com/samber/slog-sampling)':770 'github.com/samber/slog-sentry)':782 'go':47,189,205,284,332 'golang':2,6,183,685,700,715,729,740 'golang-continuous-integr':739 'golang-error-handl':1,182 'golang-nam':728 'golang-observ':699 'golang-safeti':714 'golang-samber-oop':684 'goroutin':659 'grep':95 'group':442 'guid':196 'guidelin':755 'handl':4,8,25,61,80,120,147,168,185,191,203,301,527,535,542,573,578,636 'happen':468 'http':31,358 'id':408 'idiomat':5,201 'implement':112 'independ':162,288,532,598 'indic':374 'inspect':500,517 'instead':273,420 'integr':567,696,742 'interfac':719 'intern':257,385 'interpol':405 'keep':397 'larg':581 'launch':88 'level':372,707 'line':410 'lmittmann/tint':757 'log':28,33,70,104,134,172,295,337,357,371,392,425,538,547,554,566,640,666,704,706,710 'log-and-return':103,133,639 'log.printf':341 'log/slog':785 'logger':695 'loki':439 'low':401,612 'low-cardin':400,611 'lowercas':250,462 'ma':42 'main':111 'maintain':212 'messag':391,399,459,614,678 'method':364 'middlewar':34,362,711 'miss':130 'misus':140 'mode':74,76,114,143 'must':58,226,235,248,268,292 'name':730,733 'need':348 'never':230,298,316,378,550 'new':78 'nil':718,722 'number':411 'observ':701 'one':476 'one-tim':475 'oop':687 'option':87 'packag':786 'pair':107,137 'panic':139,318,654 'panic/recover':22,170,557,652 'parallel':155,571,587 'path':365,409 'patherror':736 'pattern':536,630,693 'perform':480 'persona':43 'pii':675 'pitfal':725 'pkg.go.dev':788 'pkg.go.dev/log/slog)':787 'pr':117 'practic':85,193,221 'prealloc':478 'preced':188 'prescrib':470 'prevent':552 'principl':209 'product':38,216,346,561 'production-readi':215 'propag':63 'proper':444 'punctuat':253,464 'readi':217 'recoveri':657 'refer':446,681,756 'reliabl':48 'request':32,359,709 'reserv':323 'return':106,136,224,297,549,642 'review':113,115,750 'rich':486 'robust':200 'rule':26,169,302,543,637 'safe':525 'safeti':716 'samber':686 'samber/cc-skills-golang':181,683,698,713,727,738 'samber/oops':36,344,429,559,690,761 'samber/slog-formatter':773 'samber/slog-http':777 'samber/slog-multi':765 'samber/slog-sampling':769 'samber/slog-sentry':781 'see':682,697,712,726,737 'sentinel':20,305,473 'sentri':440 'separ':395 'sequenti':86,141 'setup':705 'sever':376 'silent':66 'singl':24,167,300,541,635 'single-handl':166 'site':426,672 'skill':177,186,195,743 'skill-golang-error-handling' 'slog':30,331,422,564,668 'source-samber' 'stack':349 'state':327 'status':366 'stori':457 'string':247,414 'structur':27,171,335,354,361,418,565,665,703 'sub':92,157,589,602,618,632,649,662 'sub-ag':91,156,588,601,617,631,648,661 'summari':222 'supersed':180 'swallow':101,128,644 'system':260 'tabl':491 'take':187 'target':160,596 'technic':380,393 'tell':455 'time':477 'tool':570,594 'topic-agent' 'topic-agent-skills' 'topic-antigravity' 'topic-claude' 'topic-claude-code' 'topic-code' 'topic-codex' 'topic-coding' 'topic-copilot' 'topic-cursor' 'topic-gemini' 'topic-gemini-cli-extension' 'trace':350 'trail':252 'translat':384 'trap':720 'treat':51 'truli':325 'type':19,278,311,483,524,616 'type-saf':523 'unaccept':73 'unrecover':326 'usag':610,655,669 'use':151,240,255,269,282,304,317,330,343,370,495,583,753 'user':383,389 'user-friend':388 'user/tenant':351 'v':258,510,626 'valid':607 'variabl':406 'verifi':627,656,667 'via':421,428,591 'violat':97,643 'vs':513,625 'w':12,243,256,505,624 'without':108,251,469 'wrap':10,131,165,237,498,622 'write':77,211","prices":[{"id":"c65c3d66-2d2c-4186-968f-4ee8a755d3a1","listingId":"3a74c0ef-8d5e-48ba-bef2-0929a19eb30a","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"samber","category":"cc-skills-golang","install_from":"skills.sh"},"createdAt":"2026-04-18T20:31:30.046Z"}],"sources":[{"listingId":"3a74c0ef-8d5e-48ba-bef2-0929a19eb30a","source":"github","sourceId":"samber/cc-skills-golang/golang-error-handling","sourceUrl":"https://github.com/samber/cc-skills-golang/tree/main/skills/golang-error-handling","isPrimary":false,"firstSeenAt":"2026-04-18T21:55:11.030Z","lastSeenAt":"2026-05-18T18:53:01.061Z"},{"listingId":"3a74c0ef-8d5e-48ba-bef2-0929a19eb30a","source":"skills_sh","sourceId":"samber/cc-skills-golang/golang-error-handling","sourceUrl":"https://skills.sh/samber/cc-skills-golang/golang-error-handling","isPrimary":true,"firstSeenAt":"2026-04-18T20:31:30.046Z","lastSeenAt":"2026-05-07T22:40:25.872Z"}],"details":{"listingId":"3a74c0ef-8d5e-48ba-bef2-0929a19eb30a","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"samber","slug":"golang-error-handling","github":{"repo":"samber/cc-skills-golang","stars":1725,"topics":["agent","agent-skills","ai","antigravity","claude","claude-code","code","codex","coding","copilot","cursor","gemini","gemini-cli-extension","openclaw","opencode","plugin","skills","skillsmp","vibe-coding"],"license":"mit","html_url":"https://github.com/samber/cc-skills-golang","pushed_at":"2026-05-18T17:36:00Z","description":"🧑‍🎨 A collection of Golang agentic skills that works","skill_md_sha":"2dc74df7ea77c6cb4735a4e908c7e6e2637c4af6","skill_md_path":"skills/golang-error-handling/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/samber/cc-skills-golang/tree/main/skills/golang-error-handling"},"layout":"multi","source":"github","category":"cc-skills-golang","frontmatter":{"name":"golang-error-handling","license":"MIT","description":"Idiomatic Golang error handling — creation, wrapping with %w, errors.Is/As, errors.Join, custom error types, sentinel errors, panic/recover, the single handling rule, structured logging with slog, HTTP request logging middleware, and samber/oops for production errors. Built to make logs usable at scale with log aggregation 3rd-party tools. Apply when creating, wrapping, inspecting, or logging errors in Go code.","compatibility":"Designed for Claude Code or similar AI coding agents, and for projects using Golang."},"skills_sh_url":"https://skills.sh/samber/cc-skills-golang/golang-error-handling"},"updatedAt":"2026-05-18T18:53:01.061Z"}}