Constant errors

February 12, 2025

Last week I talked about how to create your own errors. Expanding on that idea, here’s a trick I like to use: Constant errors!

Constants in Go are limited to simple underlying types: bool, string, and the numeric types.

If we create our own type, which both satisfies the error interface, and has such an underlying type, we can then create constant error values:


type errString string

func (e errString) Error() string {
	return string(e)
}

const ErrTooManyFrogs = errString("too many frogs")

Okay. Neat trick. But why?

It’s impossible to change the value of a constant. That’s why they’re called constants, after all! But variables can be modified.

import "io"

func init() {
	io.EOF = errors.New("LOLWUT")
}

Now, I’ve never seen code that does that. I can’t imagine why anyone would want to do that, either, except maybe for nefarious purposes. But with a constant error, that’s impossible. So small win!

I rant a bit about exported error variables in a video I made a while back, too.


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Error structs

The standard library gives us only very basic error capabilities. For the most part, we can create strings-as-errors: return errors.New("oh no") And we can wrap errors with additional textual context: if err := doSomething(); err != nil { return fmt.Errorf("doSomething: %w", err) } But the fact that the built-in error type is an interface gives us a ton more flexibility than this to include arbitrary information with our errors. There are a few ways we can include additional information in errors, and I’ll go over a few of them.


Errors

Today we’re looking at errors, and the built-in error interface. For a concept that’s so central to the Go ethos, the spec has surprisingly little to say about it: Errors The predeclared type error is defined as type error interface { Error() string } It is the conventional interface for representing an error condition, with the nil value representing no error. For instance, a function to read data from a file might be defined:


Constant lengths and expressions

A few of the built-in functions are very special, in that they can evaluate to constant expressions. len and cap are two such functions. But they aren’t always evaluated to constant expressions, sometimes they’re more normal-ish runtime functions. Length and capacity … The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or (non-constant) function calls; in this case s is not evaluated.

Get daily content like this in your inbox!

Subscribe