Skip to main content

Error Handling and Recover

In this lesson, you will learn how Mizu automatically handles errors and panics, and how you can define a custom global error handler using app.ErrorHandler. Mizu recovers from panics internally, logs errors, and keeps your app running without crashing. You only need to register an error handler if you want to customize how errors are shown to users.

Code

Create a file named main.go and add this code:
package main

import (
	"errors"
	"log"
	"net/http"
	"strings"

	"github.com/go-mizu/mizu"
)

// Custom error handler for all routes
func handleError(c *mizu.Ctx, err error) {
	c.Logger().Error("handler error", "error", err)

	if strings.Contains(err.Error(), "not found") {
		_ = c.Text(http.StatusNotFound, "Page not found")
		return
	}

	_ = c.Text(http.StatusInternalServerError, "Something went wrong: "+err.Error())
}

// Handler that returns an error
func mightFail(c *mizu.Ctx) error {
	return errors.New("something went wrong")
}

// Handler that panics
func panicHandler(c *mizu.Ctx) error {
	panic("unexpected panic occurred")
}

// Normal route
func home(c *mizu.Ctx) error {
	return c.Text(http.StatusOK, "Home page - all good")
}

func main() {
	app := mizu.New()

	// Set global error handler
	app.ErrorHandler(handleError)

	app.Get("/", home)
	app.Get("/fail", mightFail)
	app.Get("/panic", panicHandler)

	if err := app.Listen(":8080"); err != nil {
		log.Fatal(err)
	}
}

Run

Start the server:
go run .
Then open these routes:

How it works

Mizu wraps every handler with built-in recovery logic. When a handler returns an error or panics:
  1. Mizu catches the error or recovered panic.
  2. The error (or *mizu.PanicError for panics) is sent to your global error handler.
  3. If no handler is defined, Mizu logs the issue and returns a plain 500 Internal Server Error.
You can inspect the error type to customize responses. For example, to treat panics differently:
func handleError(c *mizu.Ctx, err error) {
	switch err.(type) {
	case *mizu.PanicError:
		_ = c.Text(http.StatusInternalServerError, "Internal Server Error")
	default:
		_ = c.Text(http.StatusBadRequest, "Error: "+err.Error())
	}
}
This gives you full control over how your app reports problems while Mizu ensures that it never crashes unexpectedly. Continue to the next lesson: Logging with slog to learn how to add structured, colorful, and context-aware logs to your Mizu app.