{"record":{"id":"7b8ecb93bf3974ae","repo":"Automattic/mongoose","slug":"path-path-contains-the-same-array-filter-mult","errorCode":null,"errorMessage":"Path '${path}' contains the same array filter multiple times","messagePattern":"Path '(.+?)' contains the same array filter multiple times","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/helpers/update/updatedPathsByArrayFilter.js","lineNumber":19,"sourceCode":"'use strict';\n\nconst modifiedPaths = require('./modifiedPaths');\n\nmodule.exports = function updatedPathsByArrayFilter(update) {\n  if (update == null) {\n    return {};\n  }\n  const updatedPaths = modifiedPaths(update);\n\n  return Object.keys(updatedPaths).reduce((cur, path) => {\n    const matches = path.match(/\\$\\[[^\\]]+\\]/g);\n    if (matches == null) {\n      return cur;\n    }\n    for (const match of matches) {\n      const firstMatch = path.indexOf(match);\n      if (firstMatch !== path.lastIndexOf(match)) {\n        throw new Error(`Path '${path}' contains the same array filter multiple times`);\n      }\n      cur[match.substring(2, match.length - 1)] = path.\n        substring(0, firstMatch - 1).\n        replace(/\\$\\[[^\\]]+\\]/g, '0');\n    }\n    return cur;\n  }, {});\n};\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/helpers/update/updatedPathsByArrayFilter.js#L1-L28","documentation":"MongoDB requires each array filter identifier to appear at most once per dotted update path: 'a.$[x].b.$[x]' is illegal because one identifier cannot carry two different filters within the same path. Mongoose computes the base path each identifier maps to (for versioning and discriminator handling in updatedPathsByArrayFilter) and throws this Error when the same identifier matches multiple times in one path.","triggerScenarios":"Model.updateOne({}, { $set: { 'comments.$[c].replies.$[c].text': 'hi' } }, { arrayFilters: [{ 'c.approved': true }] }) — identifier 'c' reused for both the comments and the replies level.","commonSituations":"Nested array updates where the first identifier is reused for the inner array level; template/string-built update paths that concatenate '.$[x]' repeatedly; porting raw shell queries without adding a second identifier.","solutions":["Use a distinct identifier per array level: 'comments.$[c].replies.$[r].text' with arrayFilters: [{ 'c.approved': true }, { 'r.visible': true }]","If both levels need the same condition, still use two identifiers and repeat the condition for each","Split the operation into separate updateOne calls, one per array level, if a single path is unwieldy"],"exampleFix":"// before\nawait Model.updateOne({},\n  { $set: { 'comments.$[c].replies.$[c].text': 'hi' } },\n  { arrayFilters: [{ 'c.approved': true }] });\n\n// after\nawait Model.updateOne({},\n  { $set: { 'comments.$[c].replies.$[r].text': 'hi' } },\n  { arrayFilters: [{ 'c.approved': true }, { 'r.visible': true }] });","handlingStrategy":"validation","validationCode":"// Reject update paths that reuse an array filter identifier\nfunction assertDistinctIdentifiers(update) {\n  for (const op of Object.keys(update)) {\n    for (const path of Object.keys(update[op] ?? {})) {\n      const ids = path.match(/\\$\\[([^\\]]+)\\]/g) ?? [];\n      const seen = new Set();\n      for (const id of ids) {\n        if (seen.has(id)) throw new Error(`Path '${path}' reuses identifier ${id}`);\n        seen.add(id);\n      }\n    }\n  }\n}","typeGuard":"const hasUniqueFilterIds = (path) => { const ids = path.match(/\\$\\[([^\\]]+)\\]/g) ?? []; return new Set(ids).size === ids.length; };","tryCatchPattern":"try {\n  await Model.updateOne(f, u, { arrayFilters });\n} catch (err) {\n  if (/same array filter multiple times/.test(err.message)) {\n    // rename the inner identifier (e.g. $[c].$[c] -> $[c].$[r]) and add its filter, then retry\n  } else throw err;\n}","preventionTips":["Adopt a convention of one identifier per nesting level (elem, sub, ...) for array updates","Never build update paths by string concatenation of '.$[x]' segments","Review nested-array updates against the MongoDB arrayFilters docs before shipping"],"tags":["mongoose","array-filters","update","nested-arrays"],"backgroundTag":"array-filter-invalid","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}