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
- Log the value right before the call: `console.log(typeof myPlugin)` - 'undefined' or 'object' confirms an import problem.
- Match the package export form: `const { plugin } = require('pkg')` vs `const plugin = require('pkg')`, or `import { plugin } from 'pkg'`.
- 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
- Type plugin imports explicitly in TypeScript so default/named interop mismatches surface at compile time.
- Register plugins in one place so a bad import fails once, loudly, at startup.
- Keep argument order fixed: plugin function first, options second.
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
- Invalid arguments
- Aggregate.prototype.exec() no longer accepts a callback
- Please provide an executor function
- `connection.model()` should not be run with `new`. If you ar
- The 2nd parameter to `mongoose.model()` should be a schema o
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/7f50dc7d2329f5fb.
Report an issue: GitHub.