gorilla/mux · error · ErrNotFound

no matching route was found

Error message

no matching route was found

What it means

Sentinel error mux.ErrNotFound (mux.go:22). Assigned to RouteMatch.MatchErr when no registered route matches the request. Also used internally to short-circuit subrouter matching when a query matcher fails on a matching path (route.go:68-73). With no NotFoundHandler set, Router.ServeHTTP falls back to http.NotFoundHandler (mux.go:224-226).

Source

Thrown at mux.go:22

package mux

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"regexp"
)

var (
	// ErrMethodMismatch is returned when the method in the request does not match
	// the method defined against the route.
	ErrMethodMismatch = errors.New("method is not allowed")
	// ErrNotFound is returned when no route match is found.
	ErrNotFound = errors.New("no matching route was found")
	// RegexpCompileFunc aliases regexp.Compile and enables overriding it.
	// Do not run this function from `init()` in importable packages.
	// Changing this value is not safe for concurrent use.
	RegexpCompileFunc = regexp.Compile
	// ErrMetadataKeyNotFound is returned when the specified metadata key is not present in the map
	ErrMetadataKeyNotFound = errors.New("key not found in metadata")
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route)}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//

View on GitHub (pinned to db9d1d0073)

Solutions

  1. Set router.NotFoundHandler to render the app's 404 JSON/page for clear diagnostics.
  2. Verify the request path against registered templates; mind trailing slash (consider router.StrictSlash(true)).
  3. If behind a proxy, confirm the path prefix is not being rewritten or stripped.
  4. Dump all routes via router.Walk and compare with the failing URL.

Example fix

// before
r.HandleFunc("/users/{id}", h)
// GET /user/42 (typo) -> 404

// after
r.HandleFunc("/users/{id}", h)
r.StrictSlash(true)
r.NotFoundHandler = http.HandlerFunc(notFoundJSON)
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-flight: does any route plausibly accept this path?
ok := false
_ = r.Walk(func(rt *mux.Route, _ *mux.Router, _ []*mux.Route) error {
    if tpl, err := rt.GetPathTemplate(); err == nil && matchesTemplate(tpl, req.URL.Path) {
        ok = true
    }
    return nil
})

Type guard

func isNotFound(m mux.RouteMatch) bool { return errors.Is(m.MatchErr, mux.ErrNotFound) }

Try / catch

var match mux.RouteMatch
if !r.Match(req, &match) {
    if errors.Is(match.MatchErr, mux.ErrNotFound) {
        // render 404
    }
}

Prevention

When it happens

Trigger: A request whose path/host/scheme/headers/queries match none of the registered routes; or a path matches but a .Queries(...) matcher does not, which sets ErrNotFound and breaks out of the matcher loop (route.go:68-73).

Common situations: Client URL typo; trailing-slash mismatch (StrictSlash off, client hits /users/ but route is /users); route registration skipped during refactor; reverse proxy stripping a path prefix; env-specific routes missing in staging.

Related errors


AI-assisted analysis of gorilla/mux@db9d1d0073 (2026-08-04). Data as JSON: /data/errors/6f88795ff34cb21d.json. Report an issue: GitHub.