Automattic/mongoose · error · MongooseError

You can only add an embedded discriminator on a document arr

Error message

You can only add an embedded discriminator on a document array, ${this.path} is a plain array

What it means

Calling discriminator() on an array path walks nested arrays down to the document-array schematype ($isMongooseDocumentArray) because embedded discriminators key off each subdocument's discriminatorKey. If the leaf is a plain array of primitives (or nested arrays that never reach subdocuments), there is nothing to discriminate and the call is rejected.

Source

Thrown at lib/schema/array.js:477

    return value;
  }

  throw new CastError('Array', util.inspect(value), this.path, null, this);
};

SchemaArray.prototype.$toObject = SchemaArray.prototype.toObject;

/*!
 * ignore
 */

SchemaArray.prototype.discriminator = function(...args) {
  let arr = this;
  while (arr.$isMongooseArray && !arr.$isMongooseDocumentArray) {
    arr = arr.embeddedSchemaType;
  }
  if (!arr.$isMongooseDocumentArray) {
    throw new MongooseError('You can only add an embedded discriminator on a document array, ' + this.path + ' is a plain array');
  }
  return arr.discriminator(...args);
};

/*!
 * ignore
 */

SchemaArray.prototype.clone = function() {
  const options = Object.assign({}, this.options);
  const schematype = new this.constructor(this.path, this.embeddedSchemaType, options, this.schemaOptions, this.parentSchema);
  schematype.validators = this.validators.slice();
  if (this.requiredValidator !== undefined) {
    schematype.requiredValidator = this.requiredValidator;
  }
  return schematype;
};

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Declare the path as a document array: `subs: [new Schema({ kind: String }, { discriminatorKey: 'kind' })]`, then `schema.path('subs').discriminator('X', XSchema)`.
  2. Or register embedded discriminators on the base embedded schema directly.
  3. For primitive arrays, branch in application code instead of discriminators.

Example fix

// before
const s = new Schema({ items: [String] });
s.path('items').discriminator('Note', new Schema({ text: String }));

// after
const base = new Schema({ kind: String }, { discriminatorKey: 'kind' });
const s = new Schema({ items: [base] });
s.path('items').discriminator('Note', new Schema({ text: String }));
Defensive patterns

Strategy: validation

Validate before calling

const isDocumentArrayPath = (schema, name) =>
  schema.path(name)?.$isMongooseDocumentArray === true;
if (!isDocumentArrayPath(schema, 'items')) {
  throw new Error('declare items as an array of subdocuments before adding discriminators');
}
schema.path('items').discriminator('Note', noteSchema);

Prevention

When it happens

Trigger: `schema.path('tags').discriminator('X', sub)` with `tags: [String]`; arrays declared as bare [] (Mixed elements); nested `[[String]]` walking down to a primitive leaf.

Common situations: Intending polymorphic embedded documents but declaring primitives; refactoring a subdocument array into a primitive array while keeping discriminator registration; example code copied from document-array contexts.

Related errors


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