On Errors in Golang
In Golang are two ways to signal an error in a function or method. The first is the convention to return an
as last return parameter of a function or method. The position of the return parameter is only a convention, but I’m not
aware of any library not using this convention. The
error type is a builtin interface.
The second way to signal an error is raising a panic. A panic have to be catched via the
recover method in a defer block
in the call stack. If the panic is not catched it will crash the program. This sounds like exceptions in languages like Java,
but panics should only be used if there is something unexpected and non-recoverable. In general, panics should only be
recovered to post them services like sentry.io. After delivering the panic to your observability stack,
the program should be terminated. This blog post goes into the details
of panics, defer and recover.
As described in the first paragraph, the convention is to return an error if the function can return an error. Since it is
a good practice to check every error go code has a lot of
if err != nil statements. There are a lot of people out there
hating that pattern. I got used to it. Now it shapes my way of thinking. Before doing anything with the return value of
function I think about the error cases. What should the code do in case of an error? Abort? Does the code have to clean up
any resources? Rollback any transaction? Can the code recover safely from the error? Yes this distracts from the core
business logic in the first place, but I think it leads overall to a more robust code.
The Must Pattern
However, always checking for that possible error can be annoying in cases where the function returns an error, but I know
at time of programming there will never be an error. Or, if there is an error, some fundamental assumptions broke.
A good example is the Compile function from the
regexp package. This function
has the following signature:
The function tries to compile the given string as regular expression. If the string is not a valid regular expression an error is returned. So far, the usual method signature. There is a possible error, hence return error. In the following example, the error check is never true, since I know in advance that the static expression is always a valid expression.
regexp package provides us a handy wrapper around
Compile. It is called
MustCompile and returns only a
Compile returns an error not equals nil,
MustCompile panics. This reduces the above code to:
Personally I use
MustCompile only if I know the regular expression at compile time. If my program fails to parse the
regular expression, something fundamental in the
regexp library has changed. If it depends on user input you should
MustCompile since the user may mess up your regular expression.
There are other packages providing a methods and function with a
Must prefix. E.g. MustRegister
from the prometheus client library, or MustParse from the
All those functions panic instead of returning an error. All those functions should only be used if you know for sure an
error can’t happen. Vice versa, the
Must prefix of a function indicates the user of your package that your function will
panic on error. I made it a rule of thumb for myself to prefix every function with
Must if I implement a panic in that
If your package API has many functions returning the same type, and an error you can copy the
from the template package. This wrapper has the following signature:
It accepts a Template and an error. In case
err!=nil it will panic. The example for this function shows a lesser known
feature of golang. Example:
template.New("name") returns a
Template and an error. Since
Must accept exactly those two arguments, you can just
pass the output of
Must. This saves a lot of
Must prefixed functions in the API of the template
package. Sadly, the following example will not compile:
The error message is:
If you want to pass multiple return values of a function directly into another function, the receiving function must have exactly the same input values.
In conclusion, use the prefix
Must if your method or function panics. Be careful if an API provides a
Expect that function to panic.