gin-gonic/gin · error

'${pathSeg}' in new path '${fullPath}' conflicts with existi

Error message

'${pathSeg}' in new path '${fullPath}' conflicts with existing wildcard '${n.path}' in existing prefix '${prefix}'

What it means

Thrown by (*node).addRoute in tree.go:230 when a new route's wildcard segment cannot coexist with an already-registered wildcard at the same tree position. Gin's radix tree (forked from httprouter) allows only one wildcard child per node, so two params with different names like /users/:id and /users/:name are ambiguous and rejected. The panic message prints the conflicting segment, the full new path, the existing wildcard, and the shared prefix so you can see both sides of the collision.

Source

Thrown at tree.go:230

				n = n.children[len(n.children)-1]
				n.priority++

				// Check if the wildcard matches
				if len(path) >= len(n.path) && n.path == path[:len(n.path)] &&
					// Adding a child to a catchAll is not possible
					n.nType != catchAll &&
					// Check for longer wildcard, e.g. :name and :names
					(len(n.path) >= len(path) || path[len(n.path)] == '/') {
					continue walk
				}

				// Wildcard conflict
				pathSeg := path
				if n.nType != catchAll {
					pathSeg, _, _ = strings.Cut(pathSeg, "/")
				}
				prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path
				panic("'" + pathSeg +
					"' in new path '" + fullPath +
					"' conflicts with existing wildcard '" + n.path +
					"' in existing prefix '" + prefix +
					"'")
			}

			n.insertChild(path, fullPath, handlers)
			return
		}

		// Otherwise add handle to current node
		if n.handlers != nil {
			panic("handlers are already registered for path '" + fullPath + "'")
		}
		n.handlers = handlers
		n.fullPath = fullPath
		return
	}

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Pick ONE canonical param name for that segment and use it everywhere: change /users/:name to /users/:id so both routes share the same wildcard node.
  2. If the segments genuinely carry different semantics, move one to a distinct static prefix, e.g. /users/by-name/:name vs /users/:id.
  3. Audit every router.GET/POST/... call and every router.Group(...) that introduces a :param at the conflicting position; the panic message's 'existing prefix' field names the shared ancestor.
  4. Run your route-registration code in a unit test (router :=' gin.Default(); register all routes) so the panic surfaces at test time, not in production.

Example fix

// before
router.GET("/users/:id", getUserByID)
router.GET("/users/:name", getUserByName) // panics: :name conflicts with :id

// after — disambiguate with a static prefix
router.GET("/users/:id", getUserByID)
router.GET("/users/by-name/:name", getUserByName)
Defensive patterns

Strategy: validation

Validate before calling

// Register every route inside a helper that builds a fresh Engine and
// returns the first panic, so conflicts surface in tests not in prod.
func buildRouter(routes []struct{ Method, Path string; H gin.HandlerFunc }) (*gin.Engine, error) {
    var first error
    defer func() {
        if r := recover(); r != nil {
            first = fmt.Errorf("route registration failed: %v", r)
        }
    }()
    e := gin.New()
    for _, rt := range routes {
        e.Handle(rt.Method, rt.Path, rt.H)
    }
    return e, first
}

Try / catch

// In Go, panic recovery at startup. Run route registration under recover.
func safeRegister(e *gin.Engine, method, path string, h gin.HandlerFunc) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("wildcard conflict registering %s %s: %v", method, path, r)
        }
    }()
    e.Handle(method, path, h)
    return nil
}

Prevention

When it happens

Trigger: Registering two routes whose wildcard names diverge at the same path position, e.g. router.GET("/users/:id", ...) followed by router.GET("/users/:name", ...). Also triggered by mixing a parametric segment with a static suffix that the tree cannot disambiguate, or by adding /api/:v1/resource after /api/:v2/resource on the same Engine.

Common situations: Refactoring route names during a rename, merging two routers (e.g. mounting a sub-router under /users that already declared :id), copy-pasting a route group and forgetting to rename the param consistently, or upgrading from an older Gin version where the conflict check was laxer.

Related errors


AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04). Data as JSON: /data/errors/6db51eef48e4ccf2.json. Report an issue: GitHub.