Custom error types help you give more details about problems in your program. They make it easier to understand and fix errors.
When you want to add extra information to an error, like a code or description.
When you need to check the type of error to handle it differently.
When you want to group related errors together with specific details.
Syntax
Go
type MyError struct {
Message string
Code int
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
You create a struct to hold error details.
Implement the Error() string method to satisfy the error interface.
Examples
This error type shows when a resource is missing.
Go
type NotFoundError struct {
Resource string
}
func (e NotFoundError) Error() string {
return e.Resource + " not found"
}
This error type explains what field is invalid and why.
Go
type ValidationError struct {
Field string
Problem string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("Invalid %s: %s", e.Field, e.Problem)
}
Sample Program
This program defines a custom error type MyError. The function doSomething returns this error when a condition is false. In main, we check the error and print its message and code.
Go
package main
import (
"errors""fmt"
)
type MyError struct {
Message string
Code int
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func doSomething(flag bool) error {
if !flag {
return MyError{Message: "Something went wrong", Code: 123}
}
return nil
}
func main() {
err := doSomething(false)
if err != nil {
fmt.Println(err)
var myErr MyError
if errors.As(err, &myErr) {
fmt.Printf("Custom error code: %d\n", myErr.Code)
}
} else {
fmt.Println("All good!")
}
}
OutputSuccess
Important Notes
Always implement the Error() string method so your type works as an error.
Use errors.As to check and extract your custom error type safely.
Summary
Custom error types let you add details to errors.
Define a struct and implement Error() string method.
Use errors.As to detect and handle your custom errors.
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
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.
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.
Final Answer:
To add extra information and context to errors -> Option A
Quick Check:
Custom error types add context = B [OK]
Hint: Custom errors add details, not fix or hide errors [OK]
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
Step 1: Recall how to create custom error types
In Go, a custom error type is a struct that implements the Error() string method.
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.
Final Answer:
type MyError struct { msg string } func (e MyError) Error() string { return e.msg } -> Option C
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
Step 1: Understand errors.As usage
errors.As(err, targetPtr) returns true if err matches the type pointed to by targetPtr.
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".
Final Answer:
Custom error detected -> Option B
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:
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
Step 1: Check method receiver and returned type
Error() is defined with pointer receiver (*MyError), but doSomething returns a value (MyError), not a pointer.
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.
Final Answer:
doSomething returns MyError value but Error() has pointer receiver -> Option D
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
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.
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.
Final Answer:
custom error with pointer receiver and errors.As check -> Option A