{"id":"0bcaf239cb3fc7ea","repo":"mongodb/node-mongodb-native","slug":"name-is-not-a-valid-query-modifier","errorCode":null,"errorMessage":"${name} is not a valid query modifier","messagePattern":"(.+?) is not a valid query modifier","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/cursor/find_cursor.ts","lineNumber":268,"sourceCode":"   *\n   * @param value - The $showDiskLoc option has now been deprecated and replaced with the showRecordId field. $showDiskLoc will still be accepted for OP_QUERY stye find.\n   */\n  showRecordId(value: boolean): this {\n    this.throwIfInitialized();\n    this.findOptions.showRecordId = value;\n    return this;\n  }\n\n  /**\n   * Add a query modifier to the cursor query\n   *\n   * @param name - The query modifier (must start with $, such as $orderby etc)\n   * @param value - The modifier value.\n   */\n  addQueryModifier(name: string, value: string | boolean | number | Document): this {\n    this.throwIfInitialized();\n    if (name[0] !== '$') {\n      throw new MongoInvalidArgumentError(`${name} is not a valid query modifier`);\n    }\n\n    // Strip of the $\n    const field = name.substr(1);\n\n    // NOTE: consider some TS magic for this\n    switch (field) {\n      case 'comment':\n        this.findOptions.comment = value;\n        break;\n\n      case 'explain':\n        this.findOptions.explain = value as boolean;\n        break;\n\n      case 'hint':\n        this.findOptions.hint = value as string | Document;\n        break;","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cursor/find_cursor.ts#L250-L286","documentation":"Thrown by FindCursor.addQueryModifier() (MongoInvalidArgumentError) when the name argument does not start with '$'. Query modifiers are the legacy $-prefixed operators ($orderby, $maxTimeMS, $comment, etc.), so a bare name like 'orderby' is invalid. The check is name[0] !== '$'.","triggerScenarios":"cursor.addQueryModifier('orderby', { x: 1 }) (missing $), or passing a stripped/normalized name. Any call where the first character is not '$'.","commonSituations":"Dynamically building modifier names and forgetting the '$'; refactoring that strips '$' prefixes earlier in a pipeline; copy-paste from docs that omit the prefix.","solutions":["Prefix the modifier name with '$' (e.g. '$orderby', '$maxTimeMS')","Prefer the typed builder methods (.sort(), .maxTimeMS(), .comment(), .hint()) over addQueryModifier","Validate dynamic names start with '$' before calling"],"exampleFix":"// before\ncursor.addQueryModifier('orderby', { x: 1 });\n// after\ncursor.addQueryModifier('$orderby', { x: 1 });\n// better\ncursor.sort({ x: 1 });","handlingStrategy":"validation","validationCode":"function addQueryModifierSafe(cursor, name, value) {\n  if (name == null || name[0] !== '$') {\n    throw new Error(`query modifier must start with '$': got ${name}`);\n  }\n  return cursor.addQueryModifier(name, value);\n}","typeGuard":"const isDollarPrefixed = (s) => typeof s === 'string' && s[0] === '$';","tryCatchPattern":null,"preventionTips":["Always prefix modifier names with '$'","Prefer typed builder methods (.sort, .comment, .hint) over addQueryModifier","Validate dynamic modifier names before calling"],"tags":["find","query-modifier","validation"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}