expressjs/express · error · Error
callback function required
Error message
callback function required
What it means
app.engine(ext, fn) registers a template-engine callback for a file extension. At lib/application.js:294-297 it throws 'callback function required' when fn is not a function, since Express will later invoke it as fn(path, options, callback) during rendering and anything else cannot work.
Source
Thrown at lib/application.js:296
* the same signature that Express expects: `(path, options, callback)`,
* though note that it aliases this method as `ejs.__express` internally
* so if you're using ".ejs" extensions you don't need to do anything.
*
* Some template engines do not follow this convention, the
* [Consolidate.js](https://github.com/tj/consolidate.js)
* library was created to map all of node's popular template
* engines to follow this convention, thus allowing them to
* work seamlessly within Express.
*
* @param {String} ext
* @param {Function} fn
* @return {app} for chaining
* @public
*/
app.engine = function engine(ext, fn) {
if (typeof fn !== 'function') {
throw new Error('callback function required');
}
// get file extension
var extension = ext[0] !== '.'
? '.' + ext
: ext;
// store engine
this.engines[extension] = fn;
return this;
};
/**
* Proxy to `Router#param()` with one added api feature. The _name_ parameter
* can be an array of names.
*
* See the Router#param() docs for more details.View on GitHub ↗ (pinned to a3714473fe)
Solutions
- Pass the engine's render function: app.engine('html', require('ejs').renderFile).
- For engines without an Express-compatible export, use an adapter such as consolidate: app.engine('hbs', require('consolidate').handlebars).
- Log typeof the value you're passing and inspect the engine module's exports to find the (path, options, callback) function.
Example fix
// before
app.engine('html', require('ejs'));
// after
app.engine('html', require('ejs').renderFile); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof onListen !== 'function') {
throw new TypeError('app.listen callback must be a function');
}
app.listen(port, onListen); Type guard
function isCallback(fn) {
return typeof fn === 'function';
} Try / catch
try {
app.listen(port, cb);
} catch (err) {
if (/callback function required/.test(err.message)) {
// a non-function was passed where Express requires a callback
}
throw err;
} Prevention
- Only pass a callback argument when you actually have a function; omit it entirely rather than passing null/undefined placeholders.
- Beware argument-order mistakes (e.g. passing options object where the callback goes).
- Use TypeScript definitions to catch wrong argument arity at compile time.
When it happens
Trigger: app.engine('html', undefined); passing the engine module itself rather than its render function, e.g. app.engine('html', require('ejs')) instead of require('ejs').renderFile; passing a string or options object as the second argument.
Common situations: Engines that don't expose __express and where the developer passes the wrong export (ejs.renderFile vs ejs, handlebars vs hbs.__express); consolidate.js usage errors (cons.swig vs cons.swig — must be the function property); a version upgrade of the engine package renaming its render export.
Related errors
- No default engine was specified and no extension was provide
- Module "' + mod + '" does not provide a view engine.
- unknown value for etag function: ' + val
- unknown value for query parser function: ' + val
- path must be absolute or specify root to res.sendFile
AI-assisted analysis of expressjs/express@a3714473fe (2026-07-31).
Data as JSON: /data/errors/94521fa442fdc3cd.json.
Report an issue: GitHub ↗.