gorilla/mux · error

mux: duplicated route variable %q

Error message

mux: duplicated route variable %q

What it means

Returned by uniqueVars (mux.go:550-555) when two variable-bearing matchers on the same route reuse a variable name. It is invoked during route construction from addRegexpMatcher (route.go:267, 273, 280) and stored on r.err, which disables the route. The same name cannot map to two capture slots.

Source

Thrown at mux.go:554

	}

	return np
}

// replaceURLPath prints an url.URL with a different path.
func replaceURLPath(u *url.URL, p string) string {
	// Operate on a copy of the request url.
	u2 := *u
	u2.Path = p
	return u2.String()
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

// checkPairs returns the count of strings passed in, and an error if
// the count is not an even number.
func checkPairs(pairs ...string) (int, error) {
	length := len(pairs)
	if length%2 != 0 {
		return length, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	return length, nil
}

// mapFromPairsToString converts variadic string parameters to a

View on GitHub (pinned to db9d1d0073)

Solutions

  1. Give each capture a distinct, role-prefixed name (e.g. {tenantId} for host vs {id} for path).
  2. Capture the variable once on a single matcher instead of repeating it.
  3. Call route.GetError() right after construction to surface this at startup.

Example fix

// before
r.Host("{id}.example.com").Path("/items/{id}")
// -> mux: duplicated route variable "id"

// after
r.Host("{tenantId}.example.com").Path("/items/{id}")
Defensive patterns

Strategy: validation

Validate before calling

// Reject templates that reuse a variable name across host/path/query
func distinctVars(hostTpl, pathTpl string) error {
    hv, pv := extractVars(hostTpl), extractVars(pathTpl)
    for v := range hv {
        if _, ok := pv[v]; ok {
            return fmt.Errorf("var %q reused across host and path", v)
        }
    }
    return nil
}

Type guard

// After building, confirm the route is usable
func routeOK(r *mux.Route) bool { return r != nil && r.GetError() == nil }

Try / catch

rt := r.Host(h).Path(p)
if err := rt.GetError(); err != nil {
    log.Fatalf("route build failed: %v", err)
}

Prevention

When it happens

Trigger: r.Host("{id}.example.com").Path("/items/{id}") (host and path both declare id), or r.Path("/u/{id}").Queries("ref", "{id}") (path and query both declare id).

Common situations: Copy-pasting variable names across host/path/query; renaming a var in one place but not the other; a subrouter inheriting a host var and redeclaring it on a child path.

Related errors


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