Automattic/mongoose · error · MongooseError

Provided object has both field "${name}" and its alias "${al

Error message

Provided object has both field "${name}" and its alias "${alias}"

What it means

Model.translateAliases(fields, errorOnDuplicates) rewrites aliased keys to their real schema paths. When errorOnDuplicates is true — which the query option `translateAliases: true` uses — it throws if the object contains BOTH a field and its alias, because after translation both keys would target the same path and one value would silently clobber the other. The throw fires while walking each dot-separated segment of a key against schema aliases.

Source

Thrown at lib/model.js:1958

 *
 * @param {object} fields fields/conditions that may contain aliased keys
 * @param {boolean} [errorOnDuplicates] if true, throw an error if there's both a key and an alias for that key in `fields`
 * @return {object} the translated 'pure' fields/conditions
 */
Model.translateAliases = function translateAliases(fields, errorOnDuplicates) {
  _checkContext(this, 'translateAliases');

  const translate = (key, value) => {
    let alias;
    const translated = [];
    const fieldKeys = key.split('.');
    let currentSchema = this.schema;
    for (const i in fieldKeys) {
      const name = fieldKeys[i];
      if (currentSchema?.aliases[name]) {
        alias = currentSchema.aliases[name];
        if (errorOnDuplicates && alias in fields) {
          throw new MongooseError(`Provided object has both field "${name}" and its alias "${alias}"`);
        }
        // Alias found,
        translated.push(alias);
      } else {
        alias = name;
        // Alias not found, so treat as un-aliased key
        translated.push(name);
      }

      // Check if aliased path is a schema
      if (currentSchema?.paths[alias]) {
        currentSchema = currentSchema.paths[alias].schema;
      }
      else
        currentSchema = null;
    }

    const translatedKey = translated.join('.');

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Remove one of the conflicting keys — standardize the codebase on either aliases or real field names for that object
  2. Sanitize input before the query: drop alias keys when their target field is also present (decide precedence explicitly)
  3. Keep `translateAliases` unset/false where mixed input is expected and map keys manually
  4. If both values are legitimate, rename one to a distinct schema path instead of aliasing

Example fix

// schema: new Schema({ years: { type: Number, alias: 'age' } })
// before
User.find({ years: 5, age: 5 }, null, { translateAliases: true });

// after — keep only the alias (or only the field)
User.find({ age: 5 }, null, { translateAliases: true });
Defensive patterns

Strategy: validation

Validate before calling

// Reject/drop alias-vs-field duplicates before enabling translateAliases
function hasAliasConflict(schema, fields) {
  return Object.keys(fields ?? {}).some(key => {
    const alias = schema.aliases[key];
    return alias != null && alias in fields;
  });
}

if (hasAliasConflict(User.schema, filter)) {
  filter = pickOneOfAliasPair(User.schema, filter); // your explicit precedence rule
}
const docs = await User.find(filter, null, { translateAliases: true });

Try / catch

try {
  await User.find(filter, null, { translateAliases: true });
} catch (err) {
  if (err instanceof mongoose.Error && /Provided object has both field/.test(err.message)) {
    // strip the duplicate key per your precedence rule and retry once
  }
}

Prevention

When it happens

Trigger: Schema declares `years: { type: Number, alias: 'age' }`, then `Model.find({ years: 5, age: 5 }, null, { translateAliases: true })`; same conflict in update/projection objects for findOneAndUpdate with translateAliases; direct call `Model.translateAliases({ years: 5, age: 5 }, true)`; nested paths where a subdocument schema aliases a field that also appears under its real name.

Common situations: API request bodies merged from multiple sources (query params + defaults) that carry both the alias and the field name; frontend forms switching to the alias while backend defaults still set the raw field; toggling translateAliases on after alias adoption was only partial.

Related errors


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