Golang Error Handling Quiz

Golang
0 Passed
0% acceptance

40 comprehensive questions on Golang error handling, covering error values, custom error types, fmt.Errorf with wrapping, sentinel vs typed errors, and errors.Is & errors.As — with 18 code examples demonstrating error handling patterns.

40 Questions
~80 minutes
1

Question 1

What is the error type in Golang?

A
interface{} with Error() string method
B
A built-in type like int
C
A struct with message field
D
A pointer to error struct
2

Question 2

How do you create a simple error in Golang?

go
package main

import "errors"

func main() {
    err := errors.New("something went wrong")
    println(err.Error())
}
A
errors.New(message)
B
error.New(message)
C
fmt.Errorf(message)
D
new(error)
3

Question 3

What is the zero value of error?

A
nil
B
empty error{}
C
"" (empty string)
D
Compilation error
4

Question 4

How do you check if an error occurred?

go
package main

import "fmt"

func doSomething() error {
    return nil  // or some error
}

func main() {
    if err := doSomething(); err != nil {
        fmt.Println("Error:", err)
    }
}
A
if err != nil
B
if err == nil
C
if err.Error() != ""
D
Cannot check for errors
5

Question 5

What does fmt.Errorf do?

go
package main

import "fmt"

func main() {
    err := fmt.Errorf("failed to process %s: %w", "file.txt", originalErr)
    fmt.Println(err)
}
A
Creates formatted error with optional wrapping
B
Prints error to stderr
C
Converts error to string
D
Checks if error is nil
6

Question 6

What is error wrapping?

A
Adding context to an error while preserving the original
B
Converting error to string
C
Hiding the original error
D
Replacing the error message
7

Question 7

How do you create a custom error type?

go
package main

import "fmt"

type MyError struct {
    Code int
    Msg  string
}

func (e MyError) Error() string {
    return fmt.Sprintf("code %d: %s", e.Code, e.Msg)
}

func main() {
    err := MyError{404, "not found"}
    fmt.Println(err.Error())
}
A
Define type with Error() string method
B
Use errors.New only
C
Extend built-in error type
D
Cannot create custom errors
8

Question 8

What is a sentinel error?

A
A pre-defined error value used for comparison
B
An error that occurs at runtime
C
A custom error type
D
An error with no message
9

Question 9

What is the difference between sentinel and typed errors?

A
Sentinel: global variables, Typed: custom types with data
B
Sentinel: custom types, Typed: global variables
C
They are identical
D
Sentinel errors are deprecated
10

Question 10

What does errors.Is do?

go
package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("not found")

func main() {
    err := fmt.Errorf("failed: %w", ErrNotFound)
    fmt.Println(errors.Is(err, ErrNotFound))  // true
}
A
Checks if error chain contains specific error
B
Compares error messages
C
Checks error type
D
Converts error to string
11

Question 11

What does errors.As do?

go
package main

import (
    "errors"
    "fmt"
)

type MyError struct {
    Code int
}

func (e MyError) Error() string { return "error" }

func main() {
    var myErr MyError
    err := fmt.Errorf("wrapped: %w", MyError{Code: 404})
    if errors.As(err, &myErr) {
        fmt.Println(myErr.Code)  // 404
    }
}
A
Extracts specific error type from error chain
B
Converts any error to specific type
C
Checks if error is of specific type
D
Creates new error
12

Question 12

In a web API, you're handling different types of validation errors. Should you use sentinel errors or typed errors for field validation failures?

A
Typed errors - need field name, value, and validation rule
B
Sentinel errors - simple and global
C
Either, no difference
D
Don't use errors for validation
13

Question 13

What happens when you wrap an error multiple times?

go
package main

import "fmt"

func main() {
    original := errors.New("original")
    wrapped1 := fmt.Errorf("level1: %w", original)
    wrapped2 := fmt.Errorf("level2: %w", wrapped1)
    fmt.Println(wrapped2)
}
A
Creates error chain that can be inspected
B
Overwrites previous wrapping
C
Runtime panic
D
Compilation error
14

Question 14

Why should you avoid comparing errors with == ?

go
package main

import "errors"

var ErrNotFound = errors.New("not found")

func main() {
    err := fmt.Errorf("wrapped: %w", ErrNotFound)
    // err == ErrNotFound is false!
}
A
== doesn't work with wrapped errors
B
== is deprecated
C
== compares error messages
D
No reason, == works fine
15

Question 15

How do you implement a custom error type with additional data?

go
package main

import "fmt"

type ValidationError struct {
    Field string
    Value string
    Rule  string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("validation failed for %s='%s': %s", e.Field, e.Value, e.Rule)
}

func main() {
    err := ValidationError{Field: "email", Value: "invalid", Rule: "format"}
    fmt.Println(err)
}
A
Struct with Error() method and additional fields
B
Use errors.New with JSON
C
Extend built-in error type
D
Cannot add data to errors
16

Question 16

What is the benefit of error wrapping?

A
Preserves original error for inspection while adding context
B
Makes errors smaller
C
Speeds up error creation
D
No benefit
17

Question 17

How do you handle errors that should not be wrapped?

go
package main

import "fmt"

func main() {
    err := someOperation()
    if err != nil {
        return fmt.Errorf("operation failed: %s", err.Error())  // No %w
    }
}
A
Use %s instead of %w to avoid wrapping
B
Use %v
C
Cannot avoid wrapping
D
Use errors.Wrap
18

Question 18

What is the errors package used for?

A
Error creation and inspection functions
B
Error formatting
C
Error logging
D
Error recovery
19

Question 19

In a database layer, you're implementing connection errors. Should you use a sentinel error or a typed error for connection failures?

A
Typed error - need connection details like host, port, timeout
B
Sentinel error - simple connection failed marker
C
Either, no difference
D
Don't use errors for connections
20

Question 20

What does this errors.As example demonstrate?

go
package main

import (
    "errors"
    "fmt"
)

type TimeoutError struct {
    Duration time.Duration
}

func (e TimeoutError) Error() string { return "timeout" }

func main() {
    err := fmt.Errorf("operation failed: %w", TimeoutError{5 * time.Second})
    var timeout TimeoutError
    if errors.As(err, &timeout) {
        fmt.Println("Timeout after:", timeout.Duration)
    }
}
A
Extracting typed error data from wrapped errors
B
Converting any error to TimeoutError
C
Checking if error is timeout
D
Creating new timeout error
21

Question 21

Why is error handling explicit in Golang?

A
Forces developers to think about and handle errors
B
Historical accident
C
Makes code slower
D
No reason
22

Question 22

What is the problem with this error handling?

go
package main

import "log"

func riskyOperation() error {
    return errors.New("failed")
}

func main() {
    err := riskyOperation()
    log.Fatal(err)  // Always exits
}
A
log.Fatal always terminates program
B
Should check if err != nil first
C
log.Fatal is deprecated
D
No problem
23

Question 23

How do you create an error that implements multiple interfaces?

go
package main

import "fmt"

type MyError struct {
    msg string
}

func (e MyError) Error() string { return e.msg }
func (e MyError) Timeout() bool { return true }

func main() {
    var err error = MyError{"timeout"}
    fmt.Println(err.Error())
}
A
Implement multiple methods on error type
B
Use interface composition
C
Cannot implement multiple interfaces
D
Use embedded interfaces
24

Question 24

What is the difference between %v and %w in fmt.Errorf?

go
package main

import "fmt"

func main() {
    original := errors.New("original")
    err1 := fmt.Errorf("wrapped: %v", original)  // string
    err2 := fmt.Errorf("wrapped: %w", original)  // wrapped
}
A
%v converts to string, %w wraps the error
B
They are identical
C
%w is deprecated
D
%v wraps, %w converts
25

Question 25

In a REST API, you're returning errors to clients. How should you structure error responses?

A
Use typed errors with HTTP status codes and messages
B
Return raw error strings
C
Use sentinel errors only
D
Don't return errors to clients
26

Question 26

What happens when errors.As doesn't find the target type?

go
package main

import "errors"

func main() {
    err := errors.New("simple error")
    var myErr MyError
    found := errors.As(err, &myErr)
    fmt.Println(found)  // false
}
A
Returns false, target unchanged
B
Runtime panic
C
Returns true with zero value
D
Compilation error
27

Question 27

Why should you wrap errors at API boundaries?

A
Add context about operation that failed
B
Hide internal implementation details
C
Make errors smaller
D
All of the above
28

Question 28

What is the problem with string-based error checking?

go
package main

func main() {
    err := errors.New("file not found")
    if err.Error() == "file not found" {  // Bad!
        // handle
    }
}
A
Fragile - depends on exact error message
B
Slow - string comparison
C
Cannot work with wrapped errors
D
All of the above
29

Question 29

How do you implement a temporary error for retry logic?

go
package main

import "fmt"

type TempError struct {
    msg string
}

func (e TempError) Error() string { return e.msg }
func (e TempError) Temporary() bool { return true }

func main() {
    var err error = TempError{"temporary failure"}
    // Can check if error is temporary
}
A
Implement Temporary() bool method
B
Use errors.New with special message
C
Cannot distinguish temporary errors
D
Use sentinel error
30

Question 30

What is the Go proverb about errors?

A
Errors are values
B
Errors are exceptions
C
Errors are strings
D
Errors are pointers
31

Question 31

In a microservices architecture, how should you handle errors from downstream services?

A
Wrap with service context while preserving original error
B
Replace with generic service error
C
Ignore downstream errors
D
Return errors as-is
32

Question 32

What does this error inspection demonstrate?

go
package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("not found")
var ErrPermission = errors.New("permission denied")

func main() {
    err := fmt.Errorf("db error: %w", ErrNotFound)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("Handle not found")
    } else if errors.Is(err, ErrPermission) {
        fmt.Println("Handle permission")
    }
}
A
Using errors.Is for different error conditions
B
Comparing error messages
C
Type switching on errors
D
Creating error hierarchies
33

Question 33

Why should you avoid creating error types for every error case?

A
Over-engineering - sentinel errors often sufficient
B
Performance overhead
C
Memory usage
D
Cannot create custom types
34

Question 34

What is the output of this wrapped error inspection?

go
package main

import (
    "errors"
    "fmt"
)

type MyError struct {
    Code int
}

func (e MyError) Error() string { return "my error" }

func main() {
    original := MyError{Code: 404}
    wrapped := fmt.Errorf("wrapped: %w", original)
    var target MyError
    if errors.As(wrapped, &target) {
        fmt.Println(target.Code)  // 404
    }
}
A
404
B
0
C
Compilation error
D
Runtime panic
35

Question 35

What is the most important principle of error handling in Golang?

A
Handle errors explicitly, wrap with context, inspect with errors.Is/As
B
Ignore errors when possible
C
Use panic for all errors
D
Convert all errors to strings
36

Question 36

How do you handle errors in defer statements?

go
package main

import "fmt"

func process() (err error) {
    f, err := os.Open("file.txt")
    if err != nil {
        return err
    }
    defer func() {
        if closeErr := f.Close(); closeErr != nil {
            if err == nil {
                err = closeErr
            } else {
                // handle both errors
            }
        }
    }()
    return nil
}
A
Named return value allows modifying returned error
B
Defer cannot return errors
C
Use panic in defer
D
Ignore defer errors
37

Question 37

What is the difference between error and panic?

A
Error: recoverable, Panic: unrecoverable (usually)
B
Error: crashes program, Panic: returns error
C
They are identical
D
Panic is deprecated
38

Question 38

How do you implement error aggregation?

go
package main

import "fmt"

type MultiError []error

func (me MultiError) Error() string {
    var msgs []string
    for _, err := range me {
        msgs = append(msgs, err.Error())
    }
    return fmt.Sprintf("multiple errors: %v", msgs)
}

func main() {
    errs := MultiError{errors.New("err1"), errors.New("err2")}
    fmt.Println(errs)
}
A
Slice of errors implementing Error() method
B
Use errors.Join (Go 1.20+)
C
Cannot aggregate errors
D
Use string concatenation
39

Question 39

Why should you avoid using errors in performance-critical code?

A
Error allocation can be expensive in hot paths
B
Errors are slow to check
C
Errors use too much memory
D
No performance impact
40

Question 40

What is the key insight about Golang's error handling philosophy?

A
Errors are part of API design, not exceptions
B
Errors should be avoided
C
All functions should return errors
D
Errors are only for debugging

QUIZZES IN Golang