{"id":"207b484f5f18ef73","repo":"expressjs/express","slug":"failed-to-lookup-view-name-in-views","errorCode":null,"errorMessage":"Failed to lookup view \"' + name + '\" in views ' + dirs","messagePattern":"Failed to lookup view \"' \\+ name \\+ '\" in views ' \\+ dirs","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/application.js","lineNumber":562,"sourceCode":"  if (renderOptions.cache) {\n    view = cache[name];\n  }\n\n  // view\n  if (!view) {\n    var View = this.get('view');\n\n    view = new View(name, {\n      defaultEngine: this.get('view engine'),\n      root: this.get('views'),\n      engines: engines\n    });\n\n    if (!view.path) {\n      var dirs = Array.isArray(view.root) && view.root.length > 1\n        ? 'directories \"' + view.root.slice(0, -1).join('\", \"') + '\" or \"' + view.root[view.root.length - 1] + '\"'\n        : 'directory \"' + view.root + '\"'\n      var err = new Error('Failed to lookup view \"' + name + '\" in views ' + dirs);\n      err.view = view;\n      return done(err);\n    }\n\n    // prime the cache\n    if (renderOptions.cache) {\n      cache[name] = view;\n    }\n  }\n\n  // render\n  tryRender(view, renderOptions, done);\n};\n\n/**\n * Listen for connections.\n *\n * A node `http.Server` is returned, with this","sourceCodeStart":544,"sourceCodeEnd":580,"githubUrl":"https://github.com/expressjs/express/blob/a3714473feb3d2908add734d340e7755fd85e0a3/lib/application.js#L544-L580","documentation":"During res.render()/app.render(), Express constructs a View and resolves the template file on disk (lib/application.js:549-565). If View#lookup finds no matching file under the configured 'views' root(s), view.path is empty and Express creates this error, listing the exact directories it searched, and passes it to the callback (typically ending as a 500).","triggerScenarios":"res.render('index') when views/index.<ext> doesn't exist under the 'views' setting; wrong 'views' root (relative path resolved against a different cwd); the template exists but with a different extension than the 'view engine' setting; case-sensitive filesystem mismatch (Index.ejs vs index.ejs).","commonSituations":"Deploying where the process cwd differs from development — app.set('views', './views') resolves against cwd, so use path.join(__dirname, 'views'); build/deploy pipelines that don't copy template files (Docker COPY missing the views dir); developing on macOS/Windows (case-insensitive) then deploying to Linux; monorepos where the app starts from the repo root.","solutions":["Make the views path absolute: app.set('views', path.join(__dirname, 'views')).","Verify the file exists with the expected extension in the directory named in the error message (the message lists exactly where Express looked).","Check filename case exactly matches the render() argument (Linux is case-sensitive).","Confirm your deployment artifact (Docker image, dist folder) actually contains the views directory."],"exampleFix":"// before\napp.set('views', './views'); // breaks when started from another cwd\n// after\napp.set('views', path.join(__dirname, 'views'));","handlingStrategy":"try-catch","validationCode":"const fs = require('fs');\nconst path = require('path');\nfunction viewExists(viewsDir, name, ext) {\n  return fs.existsSync(path.join(viewsDir, `${name}${ext}`));\n}\n// viewExists(app.get('views'), 'profile', '.pug')","typeGuard":null,"tryCatchPattern":"res.render(viewName, locals, (err, html) => {\n  if (err) {\n    // 'Failed to lookup view' — wrong name or wrong views dir\n    return next(err); // let the error handler return 500, never render garbage\n  }\n  res.send(html);\n});","preventionTips":["Set app.set('views', path.join(__dirname, 'views')) with an absolute path — relative paths break when the process cwd differs.","Never build view names from user input; whitelist template names.","Use res.render's callback (or a centralized error handler) so a missing template becomes a controlled 500, not a crash.","Add a startup or CI check that every view name referenced in code exists on disk — catches typos and case-sensitivity issues (Linux vs macOS/Windows)."],"tags":["express","view-resolution","rendering","deployment","filesystem"],"analyzedSha":"a3714473feb3d2908add734d340e7755fd85e0a3","analyzedAt":"2026-07-31T18:55:36.968Z","schemaVersion":2}