Automattic/mongoose · error · MongooseError

`refPath` must be a string or a function that returns a stri

Error message

`refPath` must be a string or a function that returns a string, got ${inspect(refPath)}

What it means

MongooseError raised while $set processes a path with a dynamic `refPath`: to decide whether an assigned populated document matches the ref, Mongoose resolves the refPath option. It must be the string name of a field, or a function that returns a string; a number, undefined, or any other type throws immediately.

Source

Thrown at lib/document.js:1465

      }

      // Check refPath
      let refPath = schema.options.refPath;
      if (refPath == null) {
        return false;
      }

      if (typeof refPath === 'function' && !refPath[modelSymbol]) {
        let fullPath = path;
        const fullPathWithIndexes = this.$__fullPathWithIndexes?.();
        if (fullPathWithIndexes?.length) {
          fullPath = fullPathWithIndexes + '.' + path;
        }
        refPath = refPath.call(this, this, fullPath);
      }

      if (typeof refPath !== 'string') {
        throw new MongooseError('`refPath` must be a string or a function that returns a string, got ' + inspect(refPath));
      }

      const modelName = this.ownerDocument().get(refPath);
      return modelName === model.modelName || modelName === model.baseModelName;
    })();

    let didPopulate = false;
    if (refMatches && val instanceof Document && (!val.$__.wasPopulated || utils.deepEqual(val.$__.wasPopulated.value, val._doc._id))) {
      const unpopulatedValue = schema?.$isSingleNested ? schema.cast(val, this) : val._doc._id;
      this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
      val.$__.wasPopulated = { value: unpopulatedValue };
      didPopulate = true;
    }

    let popOpts;
    const typeKey = this.$__schema.options.typeKey;
    if (schema.options &&
        Array.isArray(schema.options[typeKey]) &&

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Make refPath the string name of a field that always contains a model name
  2. If refPath is a function, guarantee a string return: `function() { return this.type || 'DefaultModel'; }`
  3. Set the type/discriminator field before assigning or populating the refPath path
  4. Skip the assignment/populate when the refPath field is missing

Example fix

// before
const schema = new Schema({
  type: String,
  item: { type: Schema.Types.ObjectId, refPath: function() { return this.type; } } // undefined when type unset
});
doc.item = populatedDoc; // refPath resolved to undefined -> MongooseError

// after
item: { type: Schema.Types.ObjectId, refPath: function() { return this.type || 'Product'; } }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure refPath resolves before assigning a populated doc
const st = doc.constructor.schema.path('item');
const rp = st.options.refPath;
const fieldName = typeof rp === 'function' ? rp.call(doc, doc, 'item') : rp;
if (typeof fieldName !== 'string' || typeof doc.get(fieldName) !== 'string') {
  throw new Error('refPath does not resolve to a model name; set the type field first');
}
doc.item = populatedDoc;

Type guard

function resolvesToModelName(doc, refPathOpt) {
  const v = typeof refPathOpt === 'function' ? refPathOpt.call(doc, doc) : refPathOpt;
  return typeof v === 'string' && typeof doc.get(v) === 'string';
}

Try / catch

try {
  doc.item = populatedDoc;
} catch (err) {
  if (/refPath` must be a string/.test(err.message)) {
    // the discriminator/type field is unset; set it (or a default model) before assigning
  } else { throw err; }
}

Prevention

When it happens

Trigger: A schema option `refPath` set to a non-string (e.g. a number or the field value itself); or a refPath function returning undefined - typically reading a discriminator/type field that is not set - when you then assign a populated document to the path (`doc.item = someDoc`) or populate it.

Common situations: Polymorphic references where the type field is optional or not yet set; refPath functions like `function() { return this.type; }` invoked before the doc has a type; copy-paste mistakes pointing refPath at a data field instead of a model-name field.

Related errors


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