Bird
Raised Fist0
Goprogramming~10 mins

Custom error types in Go - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Custom error types
Define struct for error
↓
Implement Error() method
↓
Create error instance
↓
Return or use error
↓
Check error type with type assertion
↓
Handle specific error
↓
End
Create a struct with Error() method, use it as error, then check type to handle specifically.
Execution Sample
Go
package main
import "fmt"
type MyError struct { Msg string }
func (e MyError) Error() string { return e.Msg }
func doSomething() error { return MyError{"Oops!"} }
func main() {
 err := doSomething()
 if e, ok := err.(MyError); ok {
  fmt.Println("Custom error:", e.Error())
 } else {
  fmt.Println("Other error")
 }
}
Defines a custom error type, returns it, and checks its type to print a message.
Execution Table
StepActionEvaluationResult
1Define MyError structN/AMyError type created with Msg field
2Implement Error() methodN/AMyError satisfies error interface
3Call doSomething()Returns MyError{"Oops!"}err holds MyError instance
4Type assert err to MyErrorerr.(MyError)ok is true, e is MyError{"Oops!"}
5Print custom error messagee.Error()Output: Custom error: Oops!
6End programN/AProgram exits normally
💡 Program ends after printing custom error message
Variable Tracker
VariableStartAfter Step 3After Step 4Final
errnilMyError{"Oops!"}MyError{"Oops!"}MyError{"Oops!"}
eN/AN/AMyError{"Oops!"}MyError{"Oops!"}
okN/AN/Atruetrue
Key Moments - 3 Insights
Why do we need to implement the Error() method on MyError?
Because the Error() method makes MyError satisfy the error interface, allowing it to be used as an error type (see execution_table step 2).
What does the type assertion err.(MyError) do?
It checks if err holds a MyError value and extracts it if true, as shown in execution_table step 4.
Why do we check the 'ok' variable after type assertion?
'ok' tells us if the assertion succeeded; if false, err is not MyError and we handle it differently (execution_table step 4).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 4, what is the value of 'ok' after the type assertion?
Afalse
Bnil
Ctrue
DMyError{"Oops!"}
💡 Hint
Check the 'Evaluation' and 'Result' columns at step 4 in execution_table.
At which step does the program print the custom error message?
AStep 4
BStep 5
CStep 3
DStep 6
💡 Hint
Look for the step where fmt.Println outputs the message in execution_table.
If the Error() method was missing from MyError, what would happen?
ACompilation error because MyError does not implement error interface
BRuntime panic when returning MyError
CMyError would still be used as error without issues
DThe program would print 'Other error'
💡 Hint
Recall that implementing Error() is required to satisfy the error interface (see key_moments).
Concept Snapshot
Custom error types in Go:
- Define a struct to hold error info
- Implement Error() string method on it
- Return instance as error
- Use type assertion to check error type
- Handle specific errors differently
Full Transcript
This example shows how to create a custom error type in Go by defining a struct MyError with a message field. We implement the Error() method so MyError satisfies the error interface. The function doSomething returns a MyError instance as an error. In main, we receive this error and use a type assertion to check if it is MyError. If yes, we print a custom message. The execution table traces each step: defining the struct, implementing the method, returning the error, asserting its type, and printing the message. Variables err, e, and ok track the error value and assertion success. Key moments clarify why Error() is needed, how type assertion works, and why we check the assertion result. The quiz tests understanding of these steps and consequences of missing Error(). This helps beginners see how custom errors work in Go step-by-step.

Practice

(1/5)
1. What is the main purpose of creating a custom error type in Go?
easy
A. To add extra information and context to errors
B. To make errors print in uppercase letters
C. To automatically fix errors in the code
D. To prevent errors from being returned

Solution

  1. Step 1: Understand the role of custom error types

    Custom error types allow programmers to include more details about what caused the error, beyond just a simple message.
  2. Step 2: Compare options with this understanding

    Only To add extra information and context to errors correctly describes adding extra information and context. Other options describe unrelated or incorrect behaviors.
  3. Final Answer:

    To add extra information and context to errors -> Option A
  4. Quick Check:

    Custom error types add context = B [OK]
Hint: Custom errors add details, not fix or hide errors [OK]
Common Mistakes:
  • Thinking custom errors fix problems automatically
  • Believing custom errors change error printing style
  • Assuming custom errors stop errors from returning
2. Which of the following is the correct way to define a custom error type in Go?
easy
A. type MyError string func (e MyError) Print() { fmt.Println(e) }
B. func MyError() string { return "error" }
C. type MyError struct { msg string } func (e MyError) Error() string { return e.msg }
D. var MyError = errors.New("error")

Solution

  1. Step 1: Recall how to create custom error types

    In Go, a custom error type is a struct that implements the Error() string method.
  2. Step 2: Check each option

    type MyError struct { msg string } func (e MyError) Error() string { return e.msg } defines a struct and implements Error() correctly. Options A, B, and D do not implement the Error() method properly or define a struct.
  3. Final Answer:

    type MyError struct { msg string } func (e MyError) Error() string { return e.msg } -> Option C
  4. Quick Check:

    Custom error = struct + Error() method [OK]
Hint: Custom error needs struct + Error() string method [OK]
Common Mistakes:
  • Defining error as a function without Error() method
  • Using string type without Error() method
  • Using errors.New instead of custom struct
3. What will be the output of this Go code?
package main
import (
  "errors"
  "fmt"
)
type MyError struct {
  Code int
}
func (e MyError) Error() string {
  return fmt.Sprintf("Error code: %d", e.Code)
}
func main() {
  var err error = MyError{Code: 404}
  if errors.As(err, &MyError{}) {
    fmt.Println("Custom error detected")
  } else {
    fmt.Println("Unknown error")
  }
}
medium
A. Unknown error
B. Custom error detected
C. Compilation error
D. Runtime panic

Solution

  1. Step 1: Understand errors.As usage

    errors.As(err, targetPtr) returns true if err matches the type pointed to by targetPtr.
  2. Step 2: Analyze the code's errors.As call

    &MyError{} is a pointer to type MyError. err is MyError{Code: 404}, which matches MyError exactly. errors.As succeeds and prints "Custom error detected".
  3. Final Answer:

    Custom error detected -> Option B
  4. Quick Check:

    errors.As(MyError, &MyError{}) matches [OK]
Hint: errors.As works with &MyError{} (pointer to literal) [OK]
Common Mistakes:
  • Passing &MyError{} instead of pointer to variable
  • Assuming errors.As works with value types
  • Confusing errors.Is with errors.As
4. Identify the error in this Go code snippet that tries to use a custom error type:
type MyError struct {
  Msg string
}
func (e *MyError) Error() string {
  return e.Msg
}

func doSomething() error {
  return MyError{Msg: "fail"}
}
medium
A. MyError should not have a pointer receiver for Error()
B. Error() method must return an int, not string
C. MyError struct must embed error interface
D. doSomething returns MyError value but Error() has pointer receiver

Solution

  1. Step 1: Check method receiver and returned type

    Error() is defined with pointer receiver (*MyError), but doSomething returns a value (MyError), not a pointer.
  2. Step 2: Understand interface satisfaction rules

    Because Error() has pointer receiver, only *MyError implements error interface, not MyError value. Returning MyError value causes a type mismatch.
  3. Final Answer:

    doSomething returns MyError value but Error() has pointer receiver -> Option D
  4. Quick Check:

    Pointer receiver means only pointer type implements error [OK]
Hint: Pointer receiver means return pointer, not value [OK]
Common Mistakes:
  • Returning value when method has pointer receiver
  • Thinking struct must embed error interface
  • Expecting Error() to return int
5. You want to create a custom error type that holds an error code and message, and you want to check for this error type using errors.As. Which of the following code snippets correctly implements this pattern?
hard
A. type CodeError struct { Code int; Msg string } func (e *CodeError) Error() string { return e.Msg } func main() { var err error = &CodeError{Code: 123, Msg: "fail"} var target *CodeError if errors.As(err, &target) { fmt.Println(target.Code) } }
B. type CodeError struct { Code int; Msg string } func (e CodeError) Error() string { return e.Msg } func main() { var err error = CodeError{Code: 123, Msg: "fail"} var target *CodeError if errors.As(err, &target) { fmt.Println(target.Code) } }
C. type CodeError struct { Code int; Msg string } func (e CodeError) Error() string { return e.Msg } func main() { var err error = &CodeError{Code: 123, Msg: "fail"} var target CodeError if errors.As(err, &target) { fmt.Println(target.Code) } }
D. type CodeError struct { Code int; Msg string } func (e *CodeError) Error() string { return e.Msg } func main() { var err error = CodeError{Code: 123, Msg: "fail"} var target *CodeError if errors.As(err, &target) { fmt.Println(target.Code) } }

Solution

  1. Step 1: Check receiver type and error assignment

    type CodeError struct { Code int; Msg string } func (e *CodeError) Error() string { return e.Msg } func main() { var err error = &CodeError{Code: 123, Msg: "fail"} var target *CodeError if errors.As(err, &target) { fmt.Println(target.Code) } } uses pointer receiver for Error() and assigns &CodeError{} to err, which matches the pointer receiver.
  2. Step 2: Check errors.As usage

    type CodeError struct { Code int; Msg string } func (e *CodeError) Error() string { return e.Msg } func main() { var err error = &CodeError{Code: 123, Msg: "fail"} var target *CodeError if errors.As(err, &target) { fmt.Println(target.Code) } } passes &target where target is *CodeError, which is correct usage for errors.As to detect the custom error type.
  3. Final Answer:

    custom error with pointer receiver and errors.As check -> Option A
  4. Quick Check:

    Pointer receiver + pointer error + errors.As pointer variable = A [OK]
Hint: Match pointer receiver with pointer error and pointer target in errors.As [OK]
Common Mistakes:
  • Using value receiver but returning pointer or vice versa
  • Passing non-pointer target to errors.As
  • Assigning value error but using pointer receiver
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard