(On | No) Syntactic Support for Error Handling

Go team decision and process

  • The blog post announces that Go will stop considering syntactic changes for error handling, after ~7 years, three official proposals, and hundreds of community ideas that never reached consensus.
  • Some view this as reasonable conservatism: maintaining stability, avoiding multiple styles that would spark style wars and PR bikeshedding, and respecting Go’s “one obvious way” ethos.
  • Others see it as paralysis: the team uses “no consensus” as a reason to do nothing, even though error handling repeatedly ranks as the top complaint in surveys.
  • There’s debate whether the real issue is lack of agreement on whether change is needed at all, versus inability to pick among many acceptable alternatives.

Ergonomics vs explicitness

  • Many working Go developers say they’ve grown to like if err != nil and value its explicit control flow; verbosity “fades into the background” and helps reason about reliability.
  • Critics argue verbosity hurts readability: code becomes 30–60% error boilerplate, interleaving “happy path” with trivial pass-through checks, making logic harder to follow and review.
  • A recurring theme: developers want syntactic sugar for the extremely common pattern “call, check, return/wrap error”, without changing semantics or removing explicit handling.

Proposals and why they failed

  • Ideas discussed or reinvented in the thread: or {}, Rust-style ?, Result/union types, Elixir-style ok/error tuples with a with/for-comprehension, monadic do-notation, or a generic Result[T,E] with helpers.
  • Objections raised in the thread mirror those in the proposals:
    • Hidden or implicit control flow (especially expression-level ?).
    • Locking in “error last” and (T, error) as language-enforced, not just convention.
    • Splitting the ecosystem into two idioms and creating style fights.
    • Deep incompatibility with Go’s zero-value design and lack of sum types.
  • Some commenters think the team exhausted the syntax-only design space; others say they gave up before tackling deeper semantic issues (sum types, better error typing, boundaries).

Practical issues and footguns

  • Multiple commenters highlight real bugs from:
    • Accidentally writing if err == nil instead of != nil.
    • Shadowing err with := and effectively ignoring earlier errors.
    • Dropping error return values entirely; the compiler doesn’t enforce handling.
  • Lack of built-in stack traces on errors is widely disliked; Go’s answer is manual wrapping and optional libraries, which rely on human discipline.
  • Some argue that current semantics (zero values alongside errors, no sum types, generic error interface) make it fundamentally harder to build robust, composable error APIs.

Tooling, LLMs, and IDEs

  • Several participants suggest leaning on tooling rather than new syntax:
    • Linters (errcheck, staticcheck, golangci-lint) to catch ignored errors and shadowing.
    • IDE folding/highlighting of if err != nil blocks to visually de-emphasize them.
    • LLMs or snippets to generate repetitive checks.
  • Others note writing boilerplate isn’t the main pain; reading and reviewing large amounts of near-identical error code is.

Comparisons to other languages

  • Rust’s Result and ? are often cited as a good balance: explicit, type-checked, but concise. Some point out they rely on sum types and a different type-system philosophy.
  • Exceptions (Java, Python, C#, PHP) are criticized for implicit control flow and unclear “what can fail here?”; defenders argue error boundaries and automatic stack traces are powerful, and Go has equivalent complexity spread across many if err blocks.
  • Elixir/Erlang ok/error tuples with with, Haskell/Scala monads, and Zig’s try/error traces are mentioned as attractive, but seen as mismatched with Go’s current design.

Language evolution and philosophy

  • Broader debate emerges: is Go’s extreme conservatism (generics took ~13 years, modules ~9, error syntax now frozen) a strength or slow path to irrelevance?
  • Supporters say Go’s stability and simplicity are its core value; rapid feature accretion leads to C++/Java-style complexity.
  • Critics worry that refusing to modernize ergonomics—especially around error handling and nil safety—will push new developers toward other languages, even if existing users adapt.