labstack/echo · error
static middleware failed to create sub-filesystem from confi
Error message
static middleware failed to create sub-filesystem from config.Root, error: %w
What it means
Returned by StaticConfig.ToMiddleware() (eager path, static.go:208) when fs.Sub(config.Filesystem, config.Root) fails while a custom Filesystem AND a non-'.' Root are both set. fs.Sub can fail if the root path is invalid for the filesystem implementation. This is detected at middleware construction time.
Source
Thrown at middleware/static.go:208
}
if config.DirectoryListTemplate == "" {
config.DirectoryListTemplate = directoryListHTMLTemplate
}
dirListTemplate, tErr := template.New("index").Parse(config.DirectoryListTemplate)
if tErr != nil {
return nil, fmt.Errorf("echo static middleware directory list template parsing error: %w", tErr)
}
var once *sync.Once
var fsErr error
currentFS := config.Filesystem
if config.Filesystem == nil {
once = &sync.Once{}
} else if config.Root != "." {
tmpFs, fErr := fs.Sub(config.Filesystem, path.Join(".", config.Root))
if fErr != nil {
return nil, fmt.Errorf("static middleware failed to create sub-filesystem from config.Root, error: %w", fErr)
}
currentFS = tmpFs
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) (err error) {
if config.Skipper(c) {
return next(c)
}
p := c.Request().URL.Path
if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
p = c.Param("*")
}
if config.EnablePathUnescaping {
p, err = url.PathUnescape(p)
if err != nil {
return errView on GitHub (pinned to 05489dc173)
Solutions
- Ensure config.Root matches a real directory inside the provided Filesystem (check embed directives vs Root).
- Use echo.MustSubFS(filesystem, root) which panics loudly during setup instead of failing per-request, or fs.Sub manually first to test.
- Set Root to '.' when your Filesystem is already scoped to the target directory.
- Double-check the embed path: '//go:embed static/*' embeds under 'static/', so Root should be 'static'.
Example fix
// before
//go:embed assets/*
var embedded embed.FS
cfg := middleware.StaticConfig{Filesystem: embedded, Root: "static"} // wrong: embedded under 'assets'
// after
cfg := middleware.StaticConfig{Filesystem: embedded, Root: "assets"}
// or scope it first:
sub, _ := fs.Sub(embedded, "assets")
cfg := middleware.StaticConfig{Filesystem: sub, Root: "."} Defensive patterns
Strategy: validation
Validate before calling
// Confirm the Root exists inside the filesystem before configuring Static.
func subExists(fsys fs.FS, root string) error {
sub, err := fs.Sub(fsys, root)
if err != nil { return err }
entries, err := fs.ReadDir(sub, ".")
if err != nil { return err }
_ = entries
return nil
} Prevention
- Build the sub-filesystem once with echo.MustSubFS at setup time so errors surface immediately.
- Keep embed directives and Root values in sync; verify after every embed path change.
- Use Root='.' when the Filesystem is already scoped to the target dir.
When it happens
Trigger: Providing StaticConfig.Filesystem (e.g. an embed.FS) together with a Root that does not exist within that filesystem, or a Root containing characters the FS rejects. For example Root='assets' when the embed.FS only contains 'static/'.
Common situations: Embedding files with '//go:embed static' but setting Root='assets'; using a custom fs.FS whose Sub implementation returns an error for the given path; mismatch between the directory embedded and the Root configured.
Related errors
- can not create sub FS, invalid root given, err: %w
- echo static middleware directory list template parsing error
- static middleware failed to create sub-filesystem: %w
- timeout must be set
- at least one AllowOrigins is required or UnsafeAllowOriginFu
AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04).
Data as JSON: /data/errors/3b3f1cff0238c578.json.
Report an issue: GitHub.