labstack/echo · critical
can not create sub FS, invalid root given, err: %w
Error message
can not create sub FS, invalid root given, err: %w
What it means
Panicked by MustSubFS (echo.go:950-955) when subFS returns an error from fs.Sub. fs.ValidPath forbids absolute paths, parent references (..), leading slashes, and invalid segments — so a root like "/assets", "..", or "assets/../x" triggers this panic at startup. There is no public non-panicking SubFS variant; subFS is unexported.
Source
Thrown at echo.go:953
}
return &defaultFS{
prefix: root,
fs: os.DirFS(root),
}, nil
}
return fs.Sub(currentFs, root)
}
// MustSubFS creates sub FS from current filesystem or panic on failure.
// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
//
// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with
// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, "rootDirectory") to
// create sub fs which uses necessary prefix for directory path.
func MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {
subFs, err := subFS(currentFs, fsRoot)
if err != nil {
panic(fmt.Errorf("can not create sub FS, invalid root given, err: %w", err))
}
return subFs
}
func sanitizeURI(uri string) string {
// double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
// we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
uri = "/" + strings.TrimLeft(uri, `/\`)
}
return uri
}
View on GitHub (pinned to 05489dc173)
Solutions
- Pass a relative root without a leading slash ("assets/images", not "/assets/images")
- Validate the root with fs.ValidPath(root) before calling MustSubFS
- Wrap the call in a deferred recover() when the root is dynamic
Example fix
// before
sub := echo.MustSubFS(fs, "/assets/images") // panics
// after
root := "assets/images"
if !fs.ValidPath(root) {
log.Fatalf("invalid fs root %q", root)
}
sub := echo.MustSubFS(fs, root) Defensive patterns
Strategy: validation
Validate before calling
if !fs.ValidPath(root) {
log.Fatalf("invalid fs root %q: must be relative, no leading slash, no '..'", root)
}
sub := echo.MustSubFS(fs, root) Try / catch
// recover around MustSubFS at startup when root is dynamic
defer func() {
if r := recover(); r != nil {
log.Fatalf("MustSubFS failed: %v", r)
}
}()
sub := echo.MustSubFS(fs, root) Prevention
- Validate with fs.ValidPath before calling MustSubFS
- Use relative roots without a leading slash
- Recover when the root originates from dynamic config
When it happens
Trigger: Calling echo.MustSubFS(embedFS, "/assets/images") (leading slash), MustSubFS(fs, ".."), or a root containing a segment that fails fs.ValidPath.
Common situations: Embed misconfiguration: '//go:embed assets/images' embeds files under the prefix 'assets/images', so the correct root is the relative 'assets/images' (no leading slash); Windows path leaks; dynamic roots from config.
Related errors
- static middleware failed to create sub-filesystem from confi
- echo basic-auth middleware requires a validator function
- echo body-dump middleware requires a handler function
- invalid gzip level
- timeout must be set
AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04).
Data as JSON: /data/errors/00baec7b63f057de.json.
Report an issue: GitHub.