Errors are returned as the last value of a function
Return nil if no error occurred
Errors are simply an interface that implements the Error() string function
You can create your own error types by implementing a type and creating a receiver function Error() string
// error implementationtype MyErrorType struct { a, b int}// always implement Error() functions with a pointer receiver!func (m *MyErrorType) Error() string { return fmt.Sprintf("I found an error with %v and %v.\n", m.a, m.b)}// usage of your errorfunc ReturnError() (int, error) { if thereWasAnError { return 0, &MyErrorType{1, 2} // ALWAYS return a pointer to the error struct } if simpleError { // create a new error on the fly return 0, errors.New("Error string goes here") }}// checking error typefunc CheckErrorType() { _, err := someFunc() if err != nil { var SpecificError = MyErrorType{0, 1} if errors.Is(err, &SpecificError) { // the returned error is a MyErrorType with values 0, 1 } } // errors.As(err, **) takes in a pointer to a pointer to an errorType and converts the err information into that type if possible _, err := someFunc() if err != nil { var thisError *ErrorType if errors.As(err, &thisError) { // thisError now contains all the information from the err } else { // err could not be converted to ErrorType } }}