Automattic/mongoose · error · MongooseError

First param to `schema.plugin()` must be a function, got "${

Error message

First param to `schema.plugin()` must be a function, got "${typeof fn}"

What it means

Schema#plugin() stores plugin functions so it can replay them on compiled models and discriminated schemas; the first argument must therefore be callable. Anything else - most commonly `undefined` from a broken import - is rejected on the spot, with the offending typeof shown in the message.

Source

Thrown at lib/schema.js:2256

 *     s.plugin(schema => console.log(schema.path('name').path));
 *     mongoose.model('Test', s); // Prints 'name'
 *
 * Or with Options:
 *
 *     const s = new Schema({ name: String });
 *     s.plugin((schema, opts) => console.log(opts.text, schema.path('name').path), { text: "Schema Path Name:" });
 *     mongoose.model('Test', s); // Prints 'Schema Path Name: name'
 *
 * @param {Function} plugin The Plugin's callback
 * @param {object} [opts] Options to pass to the plugin
 * @param {boolean} [opts.deduplicate=false] If true, ignore duplicate plugins (same `fn` argument using `===`)
 * @see plugins https://mongoosejs.com/docs/plugins.html
 * @api public
 */

Schema.prototype.plugin = function(fn, opts) {
  if (typeof fn !== 'function') {
    throw new MongooseError('First param to `schema.plugin()` must be a function, ' +
      'got "' + (typeof fn) + '"');
  }


  if (opts?.deduplicate) {
    for (const plugin of this.plugins) {
      if (plugin.fn === fn) {
        return this;
      }
    }
  }
  this.plugins.push({ fn: fn, opts: opts });

  fn(this, opts);
  return this;
};

/**

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Log the value right before the call: `console.log(typeof myPlugin)` - 'undefined' or 'object' confirms an import problem.
  2. Match the package export form: `const { plugin } = require('pkg')` vs `const plugin = require('pkg')`, or `import { plugin } from 'pkg'`.
  3. Keep the argument order: schema.plugin(pluginFn, options).

Example fix

// before
import slugPlugin from 'mongoose-slug-plugin';
schema.plugin(slugPlugin); // undefined: package exports a named `plugin`

// after
import { plugin as slugPlugin } from 'mongoose-slug-plugin';
schema.plugin(slugPlugin, { field: 'title' });
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof myPlugin !== 'function') {
  throw new Error(`plugin is ${typeof myPlugin} - check the import (default vs named export)`);
}
schema.plugin(myPlugin, opts);

Type guard

const isPluginFn = (fn) => typeof fn === 'function';

Prevention

When it happens

Trigger: `schema.plugin(undefined)` after `import plugin from 'pkg'` when the package only has a named export; passing the options object first (`schema.plugin({ deduplicate: true }, fn)`); importing a module namespace object instead of the function; destructuring the wrong name from the plugin package.

Common situations: A plugin package switches from default to named export across versions; TypeScript/ESM interop yields `{ default: fn }` instead of `fn`; copy-pasted plugin setup referencing a plugin never imported in that file.

Related errors


AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21). Data as JSON: /api/errors/7f50dc7d2329f5fb. Report an issue: GitHub.