{"record":{"id":"09da3c790b0e2fad","repo":"koajs/koa","slug":"middleware-must-be-a-function","errorCode":null,"errorMessage":"middleware must be a function!","messagePattern":"middleware must be a function!","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/application.js","lineNumber":168,"sourceCode":"   * @api public\n   */\n\n  inspect () {\n    return this.toJSON()\n  }\n\n  /**\n   * Use the given middleware `fn`.\n   *\n   * Old-style middleware will be converted.\n   *\n   * @param {(context: Context) => Promise<any | void>} fn\n   * @return {Application} self\n   * @api public\n   */\n\n  use (fn) {\n    if (typeof fn !== 'function') { throw new TypeError('middleware must be a function!') }\n    debug('use %s', fn._name || fn.name || '-')\n    this.middleware.push(fn)\n    return this\n  }\n\n  /**\n   * Return a request handler callback\n   * for node's native http server.\n   *\n   * @return {Function}\n   * @api public\n   */\n\n  callback () {\n    const fn = this.compose(this.middleware)\n\n    if (!this.listenerCount('error')) this.on('error', this.onerror)\n","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/koajs/koa/blob/571938d1b42d5bbfbc4f203202e1095a63003f7e/lib/application.js#L150-L186","documentation":"Thrown synchronously by app.use(fn) when the supplied middleware argument is not callable. Koa's middleware pipeline (koa-compose) dispatches each registered item as a function, so a non-function value would break invocation at request time; Koa fails fast at registration instead. The guard is a simple typeof check that surfaces a clear TypeError rather than a cryptic 'fn is not a function' later. It is a hard precondition of the public use() API.","triggerScenarios":"Calling app.use() with a value that is not a function: app.use(null), app.use(undefined), app.use({}), or app.use('router'). Most commonly app.use(router.routes) where routes is a method that was referenced but never invoked (should be router.routes()), or app.use(middleware) where the named export does not exist and resolved to undefined.","commonSituations":"Forgetting the parentheses on koa-router: app.use(router.routes) instead of app.use(router.routes()). ESM/CommonJS interop where import X from 'pkg' yields { default: fn } and the caller passes the namespace object. Refactoring a middleware module to export an object { auth, logger } and forgetting to update the call site. Conditional requires (const mw = cond ? require('./mw') : null) leaking null into use(). Typos in named imports (import { logger } from './mw' when the export is named log).","solutions":["Inspect the value passed to app.use right before the call: console.log(typeof fn, fn) and confirm it prints 'function'.","If using koa-router, invoke the generator: app.use(router.routes()) and app.use(router.allowedMethods()), with parentheses.","Verify the import resolves to the function itself, not a namespace: in ESM interop use the correct default/named binding (import fn from './mw' vs import { fn } from './mw'); log the imported binding to confirm.","Add a typeof guard or assertion before use() so failures point at the offending module.","If passing a conditional middleware, default to a no-op function (async (ctx, next) => next()) instead of null/undefined."],"exampleFix":"// before\nconst router = require('./router')\napp.use(router.routes)   // routes is a method, not the composed middleware\n\n// after\nconst router = require('./router')\napp.use(router.routes())           // invoke to get the middleware function\napp.use(router.allowedMethods())","handlingStrategy":"validation","validationCode":"// run before app.use(fn)\nfunction registerMiddleware(app, fn, label = 'middleware') {\n  if (typeof fn !== 'function') {\n    throw new TypeError(\n      `${label} must be a function, got ${fn === null ? 'null' : typeof fn} (${JSON.stringify(fn)})`\n    )\n  }\n  app.use(fn)\n}\n\n// usage\nregisterMiddleware(app, router.routes(), 'router')\nregisterMiddleware(app, require('./mw'), './mw default export')","typeGuard":"// narrows a value to a function suitable for app.use()\nfunction isMiddleware(fn) {\n  return typeof fn === 'function'\n}\n\nif (isMiddleware(mw)) {\n  app.use(mw)\n} else {\n  throw new TypeError(`Expected middleware function, received ${typeof mw}`)\n}","tryCatchPattern":null,"preventionTips":["Always invoke router middleware factories: router.routes() and router.allowedMethods(), not the bare methods.","Log the type of every imported middleware binding once at startup to catch undefined/namespace-object imports early.","Default conditional middleware to a pass-through (async (ctx, next) => next()) rather than null.","When adding ESM imports of CJS modules, verify whether the function lives at the default binding or a named one before passing it to use().","Add a tiny registerMiddleware(app, fn, label) wrapper with a typeof guard so registration failures identify the offending module by name."],"tags":["middleware","configuration","type-error","registration"],"backgroundTag":null,"analyzedSha":"571938d1b42d5bbfbc4f203202e1095a63003f7e","analyzedAt":"2026-08-04T13:07:31.940Z","contentChangedAt":"2026-08-04T13:07:31.940Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}