{"record":{"id":"8e676e4325d30a31","repo":"kataras/iris","slug":"err-8e676e","errorCode":null,"errorMessage":"err","messagePattern":"err","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"view/handlebars.go","lineNumber":74,"sourceCode":"\t// register the render helper here\n\traymond.RegisterHelper(\"render\", func(partial string, binding any) raymond.SafeString {\n\t\tcontents, err := s.executeTemplateBuf(partial, binding)\n\t\tif err != nil {\n\t\t\treturn raymond.SafeString(\"template with name: \" + partial + \" couldn't not be found.\")\n\t\t}\n\t\treturn raymond.SafeString(contents)\n\t})\n\n\treturn s\n}\n\n// RootDir sets the directory to be used as a starting point\n// to load templates from the provided file system.\nfunc (s *HandlebarsEngine) RootDir(root string) *HandlebarsEngine {\n\tif s.fs != nil && root != \"\" && root != \"/\" && root != \".\" && root != s.rootDir {\n\t\tsub, err := fs.Sub(s.fs, s.rootDir)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\ts.fs = sub // here so the \"middleware\" can work.\n\t}\n\n\ts.rootDir = filepath.ToSlash(root)\n\treturn s\n}\n\n// Name returns the handlebars engine's name.\nfunc (s *HandlebarsEngine) Name() string {\n\treturn \"Handlebars\"\n}\n\n// Ext returns the file extension which this view engine is responsible to render.\n// If the filename extension on ExecuteWriter is empty then this is appended.\nfunc (s *HandlebarsEngine) Ext() string {\n\treturn s.extension","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/view/handlebars.go#L56-L92","documentation":"HandlebarsEngine.RootDir re-roots the engine's filesystem with fs.Sub(s.fs, s.rootDir) when the engine FS is already initialized and a different root is requested. An fs.Sub error (directory not present in the FS) causes a panic because templates could never be resolved under the missing root.","triggerScenarios":"Calling h.RootDir(\"partials\") on an already-created Handlebars engine whose underlying fs does not contain \"partials\" at its current root, or chaining RootDir with an inconsistent second path.","commonSituations":"Mismatches between //go:embed directory names and the string passed to RootDir, moving templates between repo layouts after upgrading, or double-calling RootDir with different values.","solutions":["Verify the directory exists inside the engine's FS (fs.WalkDir or os.Stat for os-based FS) before calling RootDir.","Prefer passing the root at construction: view.Handlebars(view.FS(fsys), \"templates\") rather than post-construction RootDir.","Keep repeated RootDir calls consistent (same value short-circuits the failing fs.Sub branch)."],"exampleFix":"// before\neng := view.Handlebars(view.FS(assets))\neng.RootDir(\"templates\") // panics: no \"templates\" dir inside assets\n// after\neng := view.Handlebars(view.FS(assets), \"tpl\") // matches actual embedded dir","handlingStrategy":"validation","validationCode":"if _, err := fs.Stat(engineFS, \"templates\"); err != nil {\n\tlog.Fatalf(\"handlebars root missing: %v\", err)\n}\nengine.RootDir(\"templates\")","typeGuard":null,"tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tlog.Fatalf(\"Handlebars RootDir failed: %v\", r)\n\t}\n}()","preventionTips":["Set the root once at construction with view.Handlebars(view.FS(fsys), root).","Keep embedded dir names and RootDir strings in sync via a constant.","Verify template paths in a startup test."],"tags":["templates","filesystem","panic","embedded-fs"],"backgroundTag":"template-root-not-found","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}