A sentinel error gives a package a stable value that callers can compare through wrapping.

Sentinel Errors

sentinel_errors.go
package main

import (
	"errors"
	"fmt"
)

var ErrDenied = errors.New("permission denied")
var ErrClosed = errors.New("service closed")

func main() {
	var code = 
	var err error
	if code == "denied" {
		err = fmt.Errorf("authorize: %w", ErrDenied)
	} else if code == "closed" {
		err = fmt.Errorf("connect: %w", ErrClosed)
	}
	denied := errors.Is(err, ErrDenied)
	closed := errors.Is(err, ErrClosed)

	fmt.Println("code=", code)
	fmt.Println("denied=", denied)
	fmt.Println("closed=", closed)
	fmt.Println("has_error=", err != nil)
}
package main

import (
	"errors"
	"fmt"
)

var ErrDenied = errors.New("permission denied")
var ErrClosed = errors.New("service closed")

func main() {
	var code = 
	var err error
	if code == "denied" {
		err = fmt.Errorf("authorize: %w", ErrDenied)
	} else if code == "closed" {
		err = fmt.Errorf("connect: %w", ErrClosed)
	}
	denied := errors.Is(err, ErrDenied)
	closed := errors.Is(err, ErrClosed)

	fmt.Println("code=", code)
	fmt.Println("denied=", denied)
	fmt.Println("closed=", closed)
	fmt.Println("has_error=", err != nil)
}
package main

import (
	"errors"
	"fmt"
)

var ErrDenied = errors.New("permission denied")
var ErrClosed = errors.New("service closed")

func main() {
	var code = 
	var err error
	if code == "denied" {
		err = fmt.Errorf("authorize: %w", ErrDenied)
	} else if code == "closed" {
		err = fmt.Errorf("connect: %w", ErrClosed)
	}
	denied := errors.Is(err, ErrDenied)
	closed := errors.Is(err, ErrClosed)

	fmt.Println("code=", code)
	fmt.Println("denied=", denied)
	fmt.Println("closed=", closed)
	fmt.Println("has_error=", err != nil)
}
sentinel Sentinel errors should be few, named, and checked through `errors.Is` so context can still be added.