Must Functions in Go and Where They Belong in a Codebase
The Go Must convention wraps a call that returns an error and panics on failure. Learn where it belongs, write a generic Must, and see where it does harm.

Some calls cannot fail unless the programmer made a mistake. A regular expression written as a string constant is either valid or it is not, and you find out the first time the program runs. Handling that error with if err != nil produces code nobody can reach in production and nobody can recover from sensibly. Go's answer is the Must convention: a function that does the same job as the error-returning one and panics when the error is non-nil.
Tested with Go 1.25.6, macOS on Apple Silicon (arm64)
It is a narrow tool with a clear home. This note says what the home is. It is a companion to panic or error and part of the error handling guide. Everything ran on Go 1.25.6.
The standard examples
The standard library has several, and they all share a shape: a Compile or Parse that returns (T, error) and a MustCompile or Must that returns only T.
package main
import (
"fmt"
"os"
"regexp"
"text/template"
)
var (
slug = regexp.MustCompile(`^[a-z0-9]+(-[a-z0-9]+)*$`)
greet = template.Must(template.New("greet").Parse("Hello, {{.Name}}!\n"))
)
func main() {
fmt.Println(slug.MatchString("go-must-function"), slug.MatchString("Not A Slug"))
greet.Execute(os.Stdout, struct{ Name string }{"gopher"})
}true false
Hello, gopher!Both package-level variables are initialised before main runs. If the pattern or the template had a typo, the program would panic at start-up with a message pointing at the problem, on every run and on every machine. That is better than discovering it in a rarely used code path months later. regexp.Compile exists for patterns that come from users or configuration, where a bad pattern is a normal event to report.
Writing your own
Since generics, one helper covers any call shaped like (T, error):
package main
import (
"fmt"
"net/url"
"time"
)
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
var (
apiBase = Must(url.Parse("https://api.example.com/v1/"))
utc8 = Must(time.LoadLocation("Asia/Singapore"))
)
func main() {
fmt.Println(apiBase.Host, utc8)
}api.example.com Asia/SingaporeThe standard library's own proposed Must has been discussed more than once and not added, in part because it invites the misuse below. Keep your copy in an internal package, name it clearly, and use it for initialisation only.
Where it belongs
- Package-level variables built from constants: patterns, templates, parsed URLs, embedded assets.
mainorinitwhere failure means the program cannot start, such as parsing a required configuration file whose absence is a deployment error and not a user mistake.- Tests, where a failure to set up a fixture should abort the test with a clear message. Prefer
t.Fatalwhen you have a*testing.T; useMustin package-level test data.
Where it does harm
The failure mode is using it on data that varies. Must(strconv.Atoi(r.FormValue("n"))) in a handler turns a bad query string into a panic, and the server's recover turns that into a 500 and a stack trace for what should have been a 400. Anything read from a file, a request, a database or the network can fail for ordinary reasons and has to return an error. A second bad use is inside library code: a library that panics on a bad argument from its caller forces every caller to read the source to know. If a library offers a Must form, it should offer the error-returning one beside it, as regexp does.
For the broader rule about when panics are acceptable, see panic or error, and for the standard examples the documentation of regexp.MustCompile and template.Must.


