跪拜 Guibai
← All articles
Go · Frontend · Backend

Go's Error Handling Forces You to Account for Every Failure Path

By 他们叫我秃子 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Go's explicit error returns eliminate the hidden control flow of exceptions. Every caller is forced to confront failure at the point it can happen, which changes how you structure validation, resource cleanup, and API responses — especially when coming from languages where try/catch is the default.

Summary

A frontend developer learning Go walks through the language's function and error-handling model, starting from basic syntax and ending with multi-layer error propagation. Go functions can return multiple values, and the convention is to return a result alongside an error. The compiler enforces strict parameter counts and types at build time, catching mistakes that JavaScript would silently ignore.

The core pattern — `result, err := doSomething()` followed by `if err != nil` — appears in every function that can fail. Errors are not thrown; they are passed up the call stack explicitly, with each layer adding business context via `fmt.Errorf` and the `%w` verb. Ignoring an error with `_` is possible but dangerous, because the zero value of a failed result is indistinguishable from a legitimate zero.

A complete example chains `strconv.Atoi`, a `parseAge` validator, and a `createUser` function to show how low-level format errors gain context at each layer until the entry point decides whether to log, return an HTTP status, or abort.

Takeaways
Go functions declare return types after the parameter list, and multiple return values are grouped in parentheses.
The compiler rejects calls with too few or too many arguments, and mismatched types, before the program ever runs.
A function that can fail typically returns a result and an error; success is signaled by `nil` for the error.
Ignoring an error with `_` compiles but leaves the caller unable to distinguish a real zero from a failure-induced zero value.
`errors.New` creates static error messages; `fmt.Errorf` injects dynamic values into error text.
Use `%w` in `fmt.Errorf` to wrap an underlying error so the original cause is preserved for later inspection with `errors.Is` or `errors.As`.
Type conversion and business validation are separate concerns: a string may parse to an integer but still violate domain rules like age ranges.
`return` inside an `if err != nil` block exits only the current function, not the entire program.
Errors propagate upward: low-level functions report the specific failure, mid-level functions add business context, and the entry point decides the response.
Conclusions

Go's compiler acts as a first line of defense that JavaScript runtimes lack, catching argument count and type mismatches at build time.

The `value, err` convention makes the happy path and the failure path equally visible, which pressures developers to handle errors immediately rather than deferring to a distant catch block.

Wrapping errors with `%w` creates an auditable chain of causation — a sharp contrast to stack traces that show where an exception was caught but often obscure why it originated.

Coming from a frontend background, the shift from 'does it work?' to 'what happens when it breaks?' is the real threshold between UI development and backend engineering.

Concepts & terms
Multiple return values
Go functions can return more than one value, declared as a parenthesized list after the parameter list, e.g., `func calculate(a, b int) (int, int)`.
Blank identifier (`_`)
The underscore discards a return value or variable explicitly, telling the compiler 'I know this exists but I choose not to use it.'
`error` type
A built-in interface in Go that represents an error condition. A nil error means success; a non-nil error carries a descriptive message.
`errors.New`
Creates a basic error value with a fixed string message, suitable for static error conditions like 'divisor cannot be 0'.
`fmt.Errorf`
Creates a formatted error string with dynamic values, analogous to `fmt.Sprintf` but returning an `error`. The `%w` verb wraps an existing error to preserve the original cause.
Error wrapping (`%w`)
When creating a new error with `fmt.Errorf`, using `%w` instead of `%v` embeds the original error so that `errors.Is` and `errors.As` can later inspect the full error chain.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗