Automattic/mongoose · warning · TypeError

Invalid arguments

Error message

Invalid arguments

What it means

Model.create() accepts either a spread of documents or a single array plus options. There is no overloaded signature like create(doc, { session }) — the second argument would be interpreted as another document. To catch this classic mistake (gh-7535), Mongoose heuristically detects exactly two args where the last one is a ClientSession and warns that the session will not be applied, pointing you to the array form create([docs], { session }). The heuristic skips models that define their own 'session' path.

Source

Thrown at lib/aggregate.js:780

 * @api public
 */

Aggregate.prototype.redact = function(expression, thenExpr, elseExpr) {
  if (arguments.length === 3) {
    if ((typeof thenExpr === 'string' && !validRedactStringValues.has(thenExpr)) ||
      (typeof elseExpr === 'string' && !validRedactStringValues.has(elseExpr))) {
      throw new MongooseError('If thenExpr or elseExpr is string, it must be either $$DESCEND, $$PRUNE or $$KEEP');
    }

    expression = {
      $cond: {
        if: expression,
        then: thenExpr,
        else: elseExpr
      }
    };
  } else if (arguments.length !== 1) {
    throw new TypeError('Invalid arguments');
  }

  return this.append({ $redact: expression });
};

/**
 * Execute the aggregation with explain
 *
 * #### Example:
 *
 *     Model.aggregate(..).explain()
 *
 * @param {'queryPlanner'|'executionStats'|'allPlansExecution'} [verbosity]
 * @return {Promise}
 */

Aggregate.prototype.explain = async function explain(verbosity) {
  if (typeof verbosity === 'function' || typeof arguments[1] === 'function') {

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Pass an array as the first argument: await Model.create([doc], { session }).
  2. For multiple docs: await Model.create([docA, docB], { session }).
  3. Note that with the spread form (no array) the result is a single doc instead of an array — the array form also makes return shapes consistent inside transactions.
  4. Keep transaction logic in one helper so every create uses the array form by construction.

Example fix

// before
await Model.create({ name: 'x' }, { session });

// after
await Model.create([{ name: 'x' }], { session });
Defensive patterns

Strategy: validation

Validate before calling

async function createWithSession(Model, docs, session) {
  const arr = Array.isArray(docs) ? docs : [docs];
  return Model.create(arr, { session }); // array first, options second — always
}

Prevention

When it happens

Trigger: await Model.create({ name: 'x' }, { session }) — the options object holds a ClientSession; also Model.create(docA, { session: session, validateBeforeSave: false })-style spread attempts; anything where args.length === 2, the first arg is a non-null object without .session, and last.session is a ClientSession instance.

Common situations: Copy-pasting session usage from findOneAndUpdate (where an options object IS the second parameter) into create(); transaction helpers that wrap writes: sessionManager.withSession(s => Model.create(doc, { session: s })); code that worked without transactions and later gained a session argument.

Related errors


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