gin-gonic/gin · critical

URL parameters can not be used when serving a static folder

Error message

URL parameters can not be used when serving a static folder

What it means

StaticFS (routergroup.go:205) panics when the relativePath contains ':' or '*', because StaticFS itself registers a /*filepath wildcard under the hood to serve directory contents. A user-supplied ':' or '*' would collide with Gin's own wildcard and break routing, so Gin rejects it at registration time.

Source

Thrown at routergroup.go:205

	return group.returnObj()
}

// Static serves files from the given file system root.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use :
//
//	router.Static("/static", "/var/www")
func (group *RouterGroup) Static(relativePath, root string) IRoutes {
	return group.StaticFS(relativePath, Dir(root, false))
}

// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead.
// Gin by default uses: gin.Dir()
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
	if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
		panic("URL parameters can not be used when serving a static folder")
	}
	handler := group.createStaticHandler(relativePath, fs)
	urlPattern := path.Join(relativePath, "/*filepath")

	// Register GET and HEAD handlers
	group.GET(urlPattern, handler)
	group.HEAD(urlPattern, handler)
	return group.returnObj()
}

func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
	absolutePath := group.calculateAbsolutePath(relativePath)
	fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))

	return func(c *Context) {
		if _, noListing := fs.(*OnlyFilesFS); noListing {
			c.Writer.WriteHeader(http.StatusNotFound)
		}

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Mount the folder on a plain prefix with no params: router.Static("/static", "./public").
  2. To serve per-user folders, register a GET handler with c.Param and a custom http.FileServer, or chain groups (router.Group("/user/:id").Static("/files", dir)).
  3. If you need parametrised static files, write an explicit handler instead of Static/StaticFS.

Example fix

// before
router.Static("/static/:bucket", "./public")
// after
router.Static("/static", "./public")
// or parametrised:
router.GET("/:bucket/*filepath", func(c *gin.Context) {
    c.FileFromFS(filepath.Join(c.Param("bucket"), c.Param("filepath")), http.Dir("./public"))
})
Defensive patterns

Strategy: validation

Validate before calling

if strings.ContainsAny(relativePath, ":*") {
    log.Fatalf("static folder path %q must not contain URL parameters", relativePath)
}
router.StaticFS(relativePath, fs)

Prevention

When it happens

Trigger: router.Static("/static/:dir", "./public") or router.StaticFS("/files/*name", fs) — passing a param/wildcard segment to a folder-serving route.

Common situations: Confusing Static (folder) with StaticFile (single file); trying to inject path params into a static directory mount; building the path from user input that happens to contain a colon.

Related errors


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