Force error handling in Golang - or disallow ignoring return values - go

Say I have a func that returns an error:
func conditionalError() error {
if maybe {
return errors.New("here")
}
return nil
}
err := conditionalError()
but if we call it without handling the return value:
conditionalError()
is there a flag to get the compiler to complain, or maybe just an IDE setting in JetBrains or VSCode to warn about it?

There is an app for that! This type of functionality falls in the category of linters.
https://github.com/kisielk/errcheck

Related

How to report custom Go error types to Sentry?

I want my custom error to show up in Sentry, but it just grabs the underlying errorString type.
Is there a way to show operationTimeoutError instead?
Here's what I do:
type operationTimeoutError error
var errOperationTimeout operationTimeoutError = errors.New("TIMEOUT")
func foo() {
sentry.CaptureException(errOperationTimeout)
}
sentry will call the Error() method in the error you provided, which in return prints the error message of the underlying error. you can either override the Error method for the custom error type or map it to a new error with the message you intend to see in sentry. Since its likely that you are using the error for other purposes like logging, I think mapping is the better choice.
func mapError(err error)error{
switch err.(type){
case operationTimeoutError:
return errors.New("operationTimeoutError")
default:
return err
}
}
sentry.CaptureException(mapError(errOperationTimeout))

Return error from deferred function when error is already returned

Update: I think now that there is no universal answer to this question. We can return both errors using the technique explained in the answer. I think that the most important thing here is not to forget the case when we have two errors and somehow handle it.
Notes: There are many questions on SO about how to return an error from deferred function. This is not a question here.
(In Go) What is the proper way to return an error from a deferred function when the function is already returning an error. For example
func errorMaker() (err error) {
defer func() {
err = errors.New("Deferred error")
}()
err = errors.New("Some error")
return
}
func main() {
err := errorMaker()
fmt.Printf("Error: %v\n", err)
}
In the code above the error returned by the deferred function overwrites the error returned by the function. What is the canonical way to return both errors? If another programmer uses my function what result might she expect from the function when the function returns 'two errors'?
Should I use Error wrapping for this?
Additional notes:
As #Volker says in his comment I write some application specific handling for this error. Because I know what should be done based on nature of the errors.
I think my question is - if I want to return all errors from the function what is the best way to combine them in my scenario?
Disclaimer: I don't know if the following advice can be seen as "standard" or "widely-accepted".
Should I use Error wrapping for this?
Short answer: yes (I would do so).
Go 1.12 and earlier
What I do when I need my errors to convey some specific meaning, without foregoing the error interface, I create a wrapper that implements the error interface - Error() string -. This wrapper contains all extra information I need.
If the caller is aware of the existence of those extra info, it can unwrap the error with a cast and find those info.
With the added benefit that unaware callers can just handle the error as a generic error.
type MyError struct {
DeferredError error
}
// Implements 'error' interface
func (e MyError) Error() string {
// format to string
}
func someFunc() error {
// might return an instance of MyError
}
...
// Caller code
err := someFunc()
if err != nil {
if myErr, ok := err.(*MyError); ok {
// here you can access the wrapped info
fmt.Println(myErr.DeferredError)
} else {
// otherwise handle the error generically
}
}
Go 1.13 onwards
With Go.13 you can use errors.As to unwrap an error. From the official docs:
[The method] As finds the first error in err's chain that matches target, and if so, sets target to that error value and returns true. The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.
var myErr *MyError
if errors.As(err, &myErr) {
// here you can access the wrapped info
fmt.Println(myErr.DeferredError)
} else {
// otherwise handle the error generically
}
As the docs say the myErr variable is populated as a side-effect of calling As.

Linter that checks that all fields are explicitly set in struct initialisation

I want to have a static assert or linter for my go code that checks that I do not – by mistake – initialise the structs in my config file with default values for any field. I want everything to be set explicitly.
Is there a way to achieve this?
EDIT: Clarified question.
Check out the validator package.
https://gopkg.in/go-playground/validator.v9
We use it extensively in our code to validate structs.
e.g.
type Config struct {
Url string `validate:"required"`
MaxHops int `validate:"omitempty,min=0"`
MaxTerms int `validate:"omitempty,min=0"`
MaxCost float64 `validate:"omitempty,min=0"`
}
func Init(cfg *Config) error {
if err := validator.New().Struct(cfg); err != nil {
return errors.Wrap(err, "error in config")
}
//do something
}
You can use https://github.com/GaijinEntertainment/go-exhaustruct for it.
In golangci-lint, this linter is called exhaustruct and is disabled by default (see documentation).

Encountering runtime error " attempt to insert nil object "

I am trying to write a simple multiplayers Swift program using Xcode 7 beta 5. I encountered the following error at runtime:
[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
*** First throw call stack
And then I tried and error and found that this piece of code somehow introduced this error:
func setupMatchHandler() {
/* This function handles invite as sent by other users */
GKMatchmaker.sharedMatchmaker().matchForInvite(GKInvite().self , completionHandler: { (invitedMatch , invitationError) -> Void in
if invitationError != nil {
// error out
print("Game Center error: \(invitationError)")
}
if invitedMatch != nil {
// success
print("invitation received!")
}
})
}
I wonder can any expert here shed light on what went wrong here? Thanks a million!
sam
Maybe a check for (GKInvite().self != nil) could help?
It seems that it's the only thing that you are inserting via matchForInvite is this one

calling function from map[string]interface{} by giving key

I want to be able to pass function name to gin.Engine route handler. I have the following code;
// status service
type StatusService struct {
App *gin.Engine
}
func (s *StatusService) Ping(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "pong",
})
}
app := gin.Default()
// define services
statusService := &services.StatusService{
App: app,
}
ss := make(map[string]interface{})
ss["auth"] = statusService
app.GET("/ping", ss["auth"].Ping)
The compiler gives the following error;
./app.go:60: ss["auth"].Ping undefined (type interface {} has no field or method Ping)
Any ideas about how to fix that?
interface{} works for just about any type, the problem is that you've failed to assert which type the thing is. In this case you would need something like... ss["auth"].(*StatusService).Ping(myCtxInstance). This answer has a more thorough example which I'll refrain from duplicating; Go map of functions
Couple other things; if your real use case is as simple as your example just stop what you're doing and add func(ctx *gin.Context) as a second argument. Also, depending on the nature of the functions you want to use (like if they all have the same args and return types) then you might want to use a second arg for the delegates, map[string]func(argumentType) would be more appropriate.
The design you currently have pushes all errors to runtime which obviously is less desirable than the compile time safety you'd get from either of the options I touched on above.

Resources