Golang / GoLang Production Patterns and Web Standards Interview Questions
Why does Go treat errors as values instead of using exceptions, and what are the advantages?
Go deliberately chose to make errors ordinary values rather than using a try-catch exception mechanism. The error interface has exactly one method:
type error interface { Error() string }
Any function that can fail returns an error as its last return value. The caller must explicitly handle or propagate it. This design philosophy comes from Rob Pike's observation that exception-based code tends to produce programs where error handling is an afterthought — invisible control flow that developers skip over.
| Aspect | Go errors-as-values | Exception-based languages |
|---|---|---|
| Visibility | Error paths are explicit in every function signature | Error paths are hidden; callers may not know a function can fail |
| Handling | Compiler forces you to receive the error; ignoring requires _ | Uncaught exceptions terminate the program unexpectedly |
| Control flow | Linear — no hidden jumps | Non-local jumps complicate reasoning |
| Composition | Error values can carry rich context | Exception hierarchies can become complex |
| Performance | No stack unwinding — cheap | Stack unwinding has overhead |
// Every failing operation explicitly returns an error func readConfig(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("readConfig: %w", err) } var cfg Config if err := json.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("readConfig unmarshal: %w", err) } return &cfg, nil } // Caller is forced to decide what to do with the error cfg, err := readConfig("/etc/app/config.json") if err != nil { log.Fatalf("startup failed: %v", err) }
Go does have panic and recover, but they are reserved for truly unrecoverable situations (nil pointer dereferences, index out of range) or as an internal implementation detail in libraries that convert panics to errors at the public boundary.
More Related questions...