How we centralized and structured error handling in Golang

Centralized error package proposal

  • Many see the article’s “god error package” as over-centralizing domain knowledge and tightly coupling services.
  • Critics argue errors are part of each service’s API; only very low-level, cross-cutting concerns (HTTP, protocols) should be global.
  • Some feel it effectively reimplements an error “language” or exceptions inside Go, adding complexity and indirection.
  • A few defend centralization for shared schemas/standards, but think the article’s concrete design is too heavy.

Go’s error model vs alternatives

  • Strong sentiment that Go’s (T, error) style is clumsy and encourages boilerplate, especially for composing multiple calls.
  • Calls for sum types / Result-like types and a ?-style operator; Rust is often cited as a better realization of “errors as values.”
  • Others defend Go’s simplicity and explicitness, preferring visible error handling over “magic” monadic or exception-based flows.
  • Debate over exceptions: some see them as better for default bubbling; others argue they’re harder to reason about, especially without checked exceptions or effect types.

HTTP status codes vs application errors

  • Strong pushback against conflating internal errors with HTTP status codes or centrally mapping all errors to HTTP in a low level.
  • Many argue HTTP should reflect transport/request handling (200/400/401/403/404/500 etc.), while application semantics live in the body.
  • Some advocate extreme minimalism (always 200, errors in body); others highlight loss of monitoring, tooling, and infrastructure benefits.
  • Consensus trend: use a small, pragmatic subset of HTTP codes plus structured JSON error payloads.

Error context, structure, and logging

  • Broad agreement that plain strings without context are inadequate in large systems.
  • Techniques mentioned: wrapping with %w, sentinel/custom error types, attaching structured metadata (key–value pairs), and stack traces via logging libraries.
  • Some stress adding context mainly at subsystem boundaries rather than every helper function.

Fail-fast vs graceful degradation

  • One camp: treat violated invariants as bugs, assert/fail fast, and avoid running in an unknown state.
  • Opposing view: crashing entire processes (especially servers) for a single bad request is unacceptable; isolate failures per request/goroutine and recover.
  • General recognition that distinguishing “bug” vs “user/input/environment error” is crucial to choosing between aborting, retrying, or degrading gracefully.

Idiomatic Go vs “imported patterns”

  • Multiple comments warn against “writing Java/Scala/Rust in Go” with heavyweight frameworks and non-idiomatic abstractions.
  • Others counter that Go’s minimalism sometimes forces people to reinvent missing features in ad hoc, inconsistent ways.