{"record":{"id":"c5dd201d564d5b35","repo":"Automattic/mongoose","slug":"a-setter-must-be-a-function","errorCode":null,"errorMessage":"A setter must be a function.","messagePattern":"A setter must be a function\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/schemaType.js","lineNumber":829,"sourceCode":" *     const nameSchema = new Schema({ name: String, keywords: [String] });\n *     nameSchema.path('name').set(function(v) {\n *       // Need to check if `this` is a document, because in mongoose 5\n *       // setters will also run on queries, in which case `this` will be a\n *       // mongoose query object.\n *       if (this instanceof Document && v != null) {\n *         this.keywords = v.split(' ');\n *       }\n *       return v;\n *     });\n *\n * @param {Function} fn\n * @return {SchemaType} this\n * @api public\n */\n\nSchemaType.prototype.set = function(fn) {\n  if (typeof fn !== 'function') {\n    throw new TypeError('A setter must be a function.');\n  }\n  this.setters.push(fn);\n  return this;\n};\n\n/**\n * Adds a getter to this schematype.\n *\n * #### Example:\n *\n *     function dob (val) {\n *       if (!val) return val;\n *       return (val.getMonth() + 1) + \"/\" + val.getDate() + \"/\" + val.getFullYear();\n *     }\n *\n *     // defining within the schema\n *     const s = new Schema({ born: { type: Date, get: dob })\n *","sourceCodeStart":811,"sourceCodeEnd":847,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/schemaType.js#L811-L847","documentation":"SchemaType#set registers a setter function on a path and throws a TypeError for any non-function argument (lib/schemaType.js:829). Common triggers are passing a method name as a string, an undefined variable (import typo), or the already-invoked result of a function.","triggerScenarios":"`schema.path('name').set('uppercase')`; `.set(opts.setter)` where `opts.setter` is undefined; `.set(transform.v)` where `v` is a bound-method lookup that failed silently.","commonSituations":"Config-driven setter wiring; optional chaining producing undefined (`config?.post`); renaming imports and missing one usage; copying setter names from docs as strings.","solutions":["Pass a function reference: `schema.path('name').set(v => v.trim())`","Guard optional setters: `if (typeof fn === 'function') path.set(fn)`","Fix the import/variable name that resolved to undefined"],"exampleFix":"// before\nschema.path('name').set('trim'); // throws TypeError\n\n// after\nschema.path('name').set(v => v.trim());","handlingStrategy":"type-guard","validationCode":"function addSetter(schematype, fn) {\n  if (typeof fn !== 'function') {\n    throw new TypeError(`setter for ${schematype.path} must be a function, got ${typeof fn}`);\n  }\n  return schematype.set(fn);\n}","typeGuard":"const isFunction = v => typeof v === 'function';","tryCatchPattern":null,"preventionTips":["Pass function references or arrow functions, never method-name strings","Guard config-driven setters: if (typeof fn === 'function') path.set(fn)","Check imports when a setter variable is mysteriously undefined"],"tags":["mongoose","schema","setter","typeerror","validation"],"backgroundTag":"callback-must-be-function","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}