gin-gonic/gin · error

no / before catch-all in path '${fullPath}'

Error message

no / before catch-all in path '${fullPath}'

What it means

Thrown by (*node).insertChild in tree.go:363 during catch-all insertion when the byte immediately before the '*' marker is not '/'. Gin models a catch-all as a two-node structure: a parent node ending in '/' and a child holding '/*name'. If the path lacks the slash (e.g. /files*name or /foo*bar) the parent cannot be split and the tree rejects the route.

Source

Thrown at tree.go:363

			panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
		}

		if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
			pathSeg := ""
			if len(n.children) != 0 {
				pathSeg, _, _ = strings.Cut(n.children[0].path, "/")
			}
			panic("catch-all wildcard '" + path +
				"' in new path '" + fullPath +
				"' conflicts with existing path segment '" + pathSeg +
				"' in existing prefix '" + n.path + pathSeg +
				"'")
		}

		// currently fixed width 1 for '/'
		i--
		if i < 0 || path[i] != '/' {
			panic("no / before catch-all in path '" + fullPath + "'")
		}

		n.path = path[:i]

		// First node: catchAll node with empty path
		child := &node{
			wildChild: true,
			nType:     catchAll,
			fullPath:  fullPath,
		}

		n.addChild(child)
		n.indices = "/"
		n = child
		n.priority++

		// second node: node holding the variable
		child = &node{

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Insert a '/' before the '*': /files/*filepath instead of /files*filepath.
  2. When concatenating a base path and a catch-all, ensure the join introduces exactly one slash: path.Join(base, "/*filepath") or assert the boundary explicitly.
  3. Lint routes with a regex that forbids a non-'/' byte directly preceding '*'.

Example fix

// before
router.GET("/files*filepath", h)   // panics: no '/' before '*'

// after
router.GET("/files/*filepath", h)
Defensive patterns

Strategy: validation

Validate before calling

// Reject catch-all markers not preceded by '/'.
var badCatchAll = regexp.MustCompile(`[^/]\*`)

func validateCatchAllSlash(p string) error {
    if badCatchAll.MatchString(p) {
        return fmt.Errorf("path %q: '*' must be preceded by '/'", p)
    }
    return nil
}

Try / catch

func safeRegister(e *gin.Engine, method, path string, h gin.HandlerFunc) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("missing slash before catch-all in %s: %v", path, r)
        }
    }()
    e.Handle(method, path, h)
    return nil
}

Prevention

When it happens

Trigger: Registering /files*filepath, /download*archive, or any catch-all written without the separating slash. Also triggered by path manipulation that strips the slash, e.g. strings.TrimSuffix(basePath, "/") + "*all".

Common situations: Typing a catch-all quickly and omitting the slash; building paths programmatically and forgetting the delimiter; copy-pasting a param-style segment (':') and converting only the marker to '*' without adding the slash.

Related errors


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