Automattic/mongoose · error · CastError

Cast to string failed for value "${value}" (type ${valueType

Error message

Cast to string failed for value "${value}" (type ${valueType}) at path "${path}"

What it means

CastError thrown when mongoose's string caster cannot convert a value for a String path. The built-in caster (lib/cast/string.js) accepts null/undefined, strings, numbers, booleans, dates, ObjectIds, documents with a string `_id`, and objects with a custom `toString()`; it rejects plain objects (default Object.prototype.toString would give '[object Object]'), arrays, and objects without toString.

Source

Thrown at lib/schema/string.js:610

SchemaString.prototype.cast = function(value, doc, init, prev, options) {
  if (typeof value !== 'string' && SchemaType._isRef(this, value, doc, init)) {
    return this._castRef(value, doc, init, options);
  }

  let castString;
  if (typeof this._castFunction === 'function') {
    castString = this._castFunction;
  } else if (typeof this.constructor.cast === 'function') {
    castString = this.constructor.cast();
  } else {
    castString = SchemaString.cast();
  }

  try {
    return castString(value);
  } catch {
    throw new CastError('string', value, this.path, null, this);
  }
};

/*!
 * ignore
 */

function handleSingle(val, context) {
  return this.castForQuery(null, val, context);
}

/*!
 * ignore
 */

function handleArray(val, context) {
  const _this = this;
  if (!Array.isArray(val)) {

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Normalize the value to a string before assigning (`v == null ? v : String(v)`), keeping in mind `String({})` yields '[object Object]'
  2. If structured data is legitimate, change the path type to Schema.Types.Mixed or a subdocument schema
  3. Sanitize request params (flattening objects/arrays) before they reach the model
  4. Install a global custom caster via `mongoose.Schema.Types.String.cast(fn)` only if you own the coercion rules

Example fix

// before
const doc = new Model({ name: req.body.name }); // req.body.name === { first: 'A' }

// after
const raw = req.body.name;
const doc = new Model({ name: typeof raw === 'object' && raw !== null ? JSON.stringify(raw) : raw });
// or declare the path as Schema.Types.Mixed if objects are intended
Defensive patterns

Strategy: validation

Validate before calling

function isStringable(v) {
  if (v == null) return true;
  if (typeof v !== 'object') return true; // string, number, boolean, symbol cast via toString
  if (Array.isArray(v)) return false;
  if (typeof v.toString === 'function' && v.toString !== Object.prototype.toString) return true;
  return false;
}
// before assigning or querying:
if (!isStringable(value)) throw new TypeError(`field 'name' expects a string, got ${typeof value}`);

Type guard

const isStringable = v => v == null || typeof v !== 'object' || (!Array.isArray(v) && typeof v.toString === 'function' && v.toString !== Object.prototype.toString);

Try / catch

try {
  doc.name = value;
} catch (err) {
  if (err instanceof mongoose.Error.CastError && err.kind === 'string') {
    // handle bad input: log err.path, err.value and reject the payload
  } else throw err;
}

Prevention

When it happens

Trigger: `doc.name = {}` or `doc.name = ['a']`; `Model.find({ name: req.query.name })` when an Express extended query like `?name[a]=b` parses to an object; spreading API payloads that contain nested objects into a flat string field.

Common situations: Express qs parser producing arrays/objects from repeated or bracketed params; JSON payloads where a field is sometimes an object; changing a path from Mixed/Object to String while legacy data still has objects.

Related errors


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