{"id":"00baec7b63f057de","repo":"labstack/echo","slug":"can-not-create-sub-fs-invalid-root-given-err-w","errorCode":null,"errorMessage":"can not create sub FS, invalid root given, err: %w","messagePattern":"can not create sub FS, invalid root given, err: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"echo.go","lineNumber":953,"sourceCode":"\t\t}\n\t\treturn &defaultFS{\n\t\t\tprefix: root,\n\t\t\tfs:     os.DirFS(root),\n\t\t}, nil\n\t}\n\treturn fs.Sub(currentFs, root)\n}\n\n// MustSubFS creates sub FS from current filesystem or panic on failure.\n// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.\n//\n// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with\n// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, \"rootDirectory\") to\n// create sub fs which uses necessary prefix for directory path.\nfunc MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {\n\tsubFs, err := subFS(currentFs, fsRoot)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"can not create sub FS, invalid root given, err: %w\", err))\n\t}\n\treturn subFs\n}\n\nfunc sanitizeURI(uri string) string {\n\t// double slash `\\\\`, `//` or even `\\/` is absolute uri for browsers and by redirecting request to that uri\n\t// we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash\n\tif len(uri) > 1 && (uri[0] == '\\\\' || uri[0] == '/') && (uri[1] == '\\\\' || uri[1] == '/') {\n\t\turi = \"/\" + strings.TrimLeft(uri, `/\\`)\n\t}\n\treturn uri\n}\n","sourceCodeStart":935,"sourceCodeEnd":966,"githubUrl":"https://github.com/labstack/echo/blob/05489dc1730161df26b72d1ae2a3ba6fb8178fc7/echo.go#L935-L966","documentation":"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.","triggerScenarios":"Calling echo.MustSubFS(embedFS, \"/assets/images\") (leading slash), MustSubFS(fs, \"..\"), or a root containing a segment that fails fs.ValidPath.","commonSituations":"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.","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"],"exampleFix":"// before\nsub := echo.MustSubFS(fs, \"/assets/images\") // panics\n// after\nroot := \"assets/images\"\nif !fs.ValidPath(root) {\n    log.Fatalf(\"invalid fs root %q\", root)\n}\nsub := echo.MustSubFS(fs, root)","handlingStrategy":"validation","validationCode":"if !fs.ValidPath(root) {\n    log.Fatalf(\"invalid fs root %q: must be relative, no leading slash, no '..'\", root)\n}\nsub := echo.MustSubFS(fs, root)","typeGuard":null,"tryCatchPattern":"// recover around MustSubFS at startup when root is dynamic\ndefer func() {\n    if r := recover(); r != nil {\n        log.Fatalf(\"MustSubFS failed: %v\", r)\n    }\n}()\nsub := echo.MustSubFS(fs, root)","preventionTips":["Validate with fs.ValidPath before calling MustSubFS","Use relative roots without a leading slash","Recover when the root originates from dynamic config"],"tags":["filesystem","embed","startup","panic"],"analyzedSha":"05489dc1730161df26b72d1ae2a3ba6fb8178fc7","analyzedAt":"2026-08-04T21:32:47.783Z","schemaVersion":2}