mongodb/node-mongodb-native · error · MongoInvalidArgumentError

${name} is not a valid query modifier

Error message

${name} is not a valid query modifier

What it means

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] !== '$'.

Source

Thrown at src/cursor/find_cursor.ts:268

   *
   * @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.
   */
  showRecordId(value: boolean): this {
    this.throwIfInitialized();
    this.findOptions.showRecordId = value;
    return this;
  }

  /**
   * Add a query modifier to the cursor query
   *
   * @param name - The query modifier (must start with $, such as $orderby etc)
   * @param value - The modifier value.
   */
  addQueryModifier(name: string, value: string | boolean | number | Document): this {
    this.throwIfInitialized();
    if (name[0] !== '$') {
      throw new MongoInvalidArgumentError(`${name} is not a valid query modifier`);
    }

    // Strip of the $
    const field = name.substr(1);

    // NOTE: consider some TS magic for this
    switch (field) {
      case 'comment':
        this.findOptions.comment = value;
        break;

      case 'explain':
        this.findOptions.explain = value as boolean;
        break;

      case 'hint':
        this.findOptions.hint = value as string | Document;
        break;

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Prefix the modifier name with '$' (e.g. '$orderby', '$maxTimeMS')
  2. Prefer the typed builder methods (.sort(), .maxTimeMS(), .comment(), .hint()) over addQueryModifier
  3. Validate dynamic names start with '$' before calling

Example fix

// before
cursor.addQueryModifier('orderby', { x: 1 });
// after
cursor.addQueryModifier('$orderby', { x: 1 });
// better
cursor.sort({ x: 1 });
Defensive patterns

Strategy: validation

Validate before calling

function addQueryModifierSafe(cursor, name, value) {
  if (name == null || name[0] !== '$') {
    throw new Error(`query modifier must start with '$': got ${name}`);
  }
  return cursor.addQueryModifier(name, value);
}

Type guard

const isDollarPrefixed = (s) => typeof s === 'string' && s[0] === '$';

Prevention

When it happens

Trigger: cursor.addQueryModifier('orderby', { x: 1 }) (missing $), or passing a stripped/normalized name. Any call where the first character is not '$'.

Common situations: Dynamically building modifier names and forgetting the '$'; refactoring that strips '$' prefixes earlier in a pipeline; copy-paste from docs that omit the prefix.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/0bcaf239cb3fc7ea.json. Report an issue: GitHub.