Automattic/mongoose · error · MongooseError
Invalid project() argument. Must be string or object
Error message
Invalid project() argument. Must be string or object
What it means
utils.errorToPOJO() converts an Error instance into a plain object by copying its own enumerable and non-enumerable property names. Because the whole point is to serialize error metadata (stack, message, code) for transport or aggregation, it refuses anything that is not an instanceof Error and throws a plain Error with this message. Mongoose uses it internally when aggregating errors (for example in Model.create() with aggregateErrors and in bulk write error reporting).
Source
Thrown at lib/aggregate.js:264
const fields = {};
if (typeof arg === 'object' && !Array.isArray(arg)) {
Object.keys(arg).forEach(function(field) {
fields[field] = arg[field];
});
} else if (arguments.length === 1 && typeof arg === 'string') {
arg.split(/\s+/).forEach(function(field) {
if (!field) {
return;
}
const include = field[0] === '-' ? 0 : 1;
if (include === 0) {
field = field.substring(1);
}
fields[field] = include;
});
} else {
throw new MongooseError('Invalid project() argument. Must be string or object');
}
return this.append({ $project: fields });
};
/**
* Appends a new custom $group operator to this aggregate pipeline.
*
* #### Example:
*
* aggregate.group({ _id: "$department" });
*
* @see $group https://www.mongodb.com/docs/manual/reference/aggregation/group/
* @method group
* @memberOf Aggregate
* @instance
* @param {object} arg $group operator contents
* @return {Aggregate}View on GitHub (pinned to 49cdab0136)
Solutions
- Pass an actual Error instance: errorToPOJO(new Error('...')).
- If the value may be a plain object or string, re-wrap it first: typeof x === 'string' || !(x instanceof Error) ? new Error(x) : x.
- For cross-realm errors (vm, Jest fake modules), construct errors in the main realm, or duck-type check (x && x.stack && x.message) and wrap.
Example fix
// before
utils.errorToPOJO({ message: 'boom', code: 42 }); // throws
// after
const err = maybeErr instanceof Error ? maybeErr : new Error(String(maybeErr?.message ?? maybeErr));
const pojo = utils.errorToPOJO(err); Defensive patterns
Strategy: type-guard
Validate before calling
function toErrorPojoSafe(value) {
const err = value instanceof Error ? value : new Error(String(value?.message ?? value));
return utils.errorToPOJO(err);
} Type guard
const isErrorLike = (x) => x instanceof Error || (x != null && typeof x === 'object' && typeof x.stack === 'string' && typeof x.message === 'string');
Try / catch
try {
return utils.errorToPOJO(maybeError);
} catch (err) {
// re-wrap non-Error input and retry once
return utils.errorToPOJO(new Error(String(maybeError?.message ?? maybeError)));
} Prevention
- Always pass Error instances across library boundaries; never pre-serialize errors to POJOs.
- In Jest/vm/worker contexts, construct errors in the main realm to keep instanceof working.
- Duck-type check (message + stack) when receiving errors from other packages and wrap if needed.
When it happens
Trigger: Calling utils.errorToPOJO('string') or errorToPOJO({ message: 'x' }) directly; passing a mongoose error-like plain object or an error from another realm/VM (e.g. errors created inside a Jest module registry or vm context fail instanceof Error); libraries that wrap errors as POJOs before Mongoose aggregates them.
Common situations: Cross-realm errors in Jest or worker_threads where instanceof fails; user code that normalizes errors to plain objects and then passes them back into an API expecting Error instances; retry wrappers that store err.toJSON() and later feed it to error aggregation.
Related errors
- Arguments must be aggregate pipeline operators
- Invalid addFields() argument. Must be an object
- Invalid `path`. Must be either string or array. Got "${path}
- Cannot set both `validateAllPaths` and `pathsToSkip`
- Cannot set both `validateAllPaths` and `pathsToValidate`
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/8833616738c4d720.
Report an issue: GitHub.