package config import ( "errors" "fmt" ) var NotInitialized error = errors.New("your application config not initialized") var VersionMismatch error = errors.New("your PB version does not match") var ErrEmpty error = fmt.Errorf("config file was empty") var ErrMarshal error = fmt.Errorf("protobuf parse error") // more complicated errors. good idea or bad idea? // Finally, declare a package-level variable of your new type. // This is the "sentinel" error that users will compare against. var ErrNotInitialized = NotInitializedError{} func ErrdKeyFalse(varname string) error { return errors.New("config key '" + varname + "' was not 'true'") } func ErrdKeyNotSet(varname string) error { return errors.New("config key '" + varname + "' was not set") } // thanks gemini for this example custom error example // --- 1. A Custom Error Type for "Not Initialized" --- // First, define a new, named type for your error. A struct is common. type NotInitializedError struct{} // Now, attach the Error() method to your new type. This makes it // satisfy the built-in 'error' interface. func (e NotInitializedError) Error() string { return "your application config not initialized" } // (Your Goal) Attach a custom String() method for pretty printing. // This will be used by fmt.Println, for example. func (e NotInitializedError) String() string { return "func main() didn't initialize this" } // --- 2. A Custom Error Type with an Is() Method --- // Let's make a more complex error for key-not-set issues. type KeyNotSetError struct { KeyName string // It can hold data! } // Make it satisfy the 'error' interface. func (e KeyNotSetError) Error() string { return fmt.Sprintf("config key '%s' was not set", e.KeyName) } // (Your Goal) Define a custom Is() method. // errors.Is(someError, ErrKeyNotSet) will call this method. func (e KeyNotSetError) Is(target error) bool { // We can check if the target is of the same type. // This allows errors.Is(err, KeyNotSetError{}) to work, // checking for the general *type* of error. _, ok := target.(KeyNotSetError) return ok } // A helper function to create this error. func NewKeyNotSetError(varname string) error { return KeyNotSetError{KeyName: varname} } // A generic sentinel error for this category. var ErrKeyNotSet = KeyNotSetError{} /* // --- Example Usage --- func checkConfig() error { // Pretend the config is not initialized. return ErrNotInitialized } func checkKey(key string) error { // Pretend a specific key is not set. return NewKeyNotSetError(key) } func main() { // --- Test Case 1: The NotInitializedError --- err1 := checkConfig() // errors.Is() works perfectly because it compares the variable directly. if errors.Is(err1, ErrNotInitialized) { fmt.Println("Check 1: errors.Is correctly identified ErrNotInitialized.") } // fmt.Println will use your custom String() method! fmt.Println("Check 2: Printing the error uses the custom String() method:") fmt.Println(err1) fmt.Println() // --- Test Case 2: The KeyNotSetError --- err2 := checkKey("database_url") // This works because of your custom Is() method! // We are checking if err2 is of the *type* KeyNotSetError. if errors.Is(err2, ErrKeyNotSet) { fmt.Println("Check 3: errors.Is correctly identified the general KeyNotSetError type.") } // You can also get the underlying error to inspect its data. var keyErr KeyNotSetError if errors.As(err2, &keyErr) { fmt.Printf("Check 4: errors.As extracted the error data. Key not set: %s\n", keyErr.KeyName) } } */