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

  1. Pass a relative root without a leading slash ("assets/images", not "/assets/images")
  2. Validate the root with fs.ValidPath(root) before calling MustSubFS
  3. 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

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


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/00baec7b63f057de.json. Report an issue: GitHub.