{"record":{"id":"94e9acb0ad9f9f94","repo":"Automattic/mongoose","slug":"provided-object-has-both-field-name-and-its-a","errorCode":null,"errorMessage":"Provided object has both field \"${name}\" and its alias \"${alias}\"","messagePattern":"Provided object has both field \"(.+?)\" and its alias \"(.+?)\"","errorType":"exception","errorClass":"MongooseError","httpStatus":null,"severity":"error","filePath":"lib/model.js","lineNumber":1958,"sourceCode":" *\n * @param {object} fields fields/conditions that may contain aliased keys\n * @param {boolean} [errorOnDuplicates] if true, throw an error if there's both a key and an alias for that key in `fields`\n * @return {object} the translated 'pure' fields/conditions\n */\nModel.translateAliases = function translateAliases(fields, errorOnDuplicates) {\n  _checkContext(this, 'translateAliases');\n\n  const translate = (key, value) => {\n    let alias;\n    const translated = [];\n    const fieldKeys = key.split('.');\n    let currentSchema = this.schema;\n    for (const i in fieldKeys) {\n      const name = fieldKeys[i];\n      if (currentSchema?.aliases[name]) {\n        alias = currentSchema.aliases[name];\n        if (errorOnDuplicates && alias in fields) {\n          throw new MongooseError(`Provided object has both field \"${name}\" and its alias \"${alias}\"`);\n        }\n        // Alias found,\n        translated.push(alias);\n      } else {\n        alias = name;\n        // Alias not found, so treat as un-aliased key\n        translated.push(name);\n      }\n\n      // Check if aliased path is a schema\n      if (currentSchema?.paths[alias]) {\n        currentSchema = currentSchema.paths[alias].schema;\n      }\n      else\n        currentSchema = null;\n    }\n\n    const translatedKey = translated.join('.');","sourceCodeStart":1940,"sourceCodeEnd":1976,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/model.js#L1940-L1976","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove one of the conflicting keys — standardize the codebase on either aliases or real field names for that object","Sanitize input before the query: drop alias keys when their target field is also present (decide precedence explicitly)","Keep `translateAliases` unset/false where mixed input is expected and map keys manually","If both values are legitimate, rename one to a distinct schema path instead of aliasing"],"exampleFix":"// schema: new Schema({ years: { type: Number, alias: 'age' } })\n// before\nUser.find({ years: 5, age: 5 }, null, { translateAliases: true });\n\n// after — keep only the alias (or only the field)\nUser.find({ age: 5 }, null, { translateAliases: true });","handlingStrategy":"validation","validationCode":"// Reject/drop alias-vs-field duplicates before enabling translateAliases\nfunction hasAliasConflict(schema, fields) {\n  return Object.keys(fields ?? {}).some(key => {\n    const alias = schema.aliases[key];\n    return alias != null && alias in fields;\n  });\n}\n\nif (hasAliasConflict(User.schema, filter)) {\n  filter = pickOneOfAliasPair(User.schema, filter); // your explicit precedence rule\n}\nconst docs = await User.find(filter, null, { translateAliases: true });","typeGuard":null,"tryCatchPattern":"try {\n  await User.find(filter, null, { translateAliases: true });\n} catch (err) {\n  if (err instanceof mongoose.Error && /Provided object has both field/.test(err.message)) {\n    // strip the duplicate key per your precedence rule and retry once\n  }\n}","preventionTips":["Standardize each object producer (form, API client, seeder) on either aliases or raw field names — never mix","When merging objects that may contain aliases, dedupe with a schema.aliases-aware merge helper before querying","Add a unit test that feeds every public filter-bearing endpoint an alias+field pair once"],"tags":["mongoose","alias","translatealiases","conflicting-keys","query-options"],"backgroundTag":"field-alias-conflict","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}