Automattic/mongoose · error · Error

Can't use ${$conditional} with Buffer.

Error message

Can't use ${$conditional} with Buffer.

What it means

SchemaBuffer.castForQuery throws a plain Error when a query filter applies an operator that has no registered handler for Buffer paths. Buffer's handler set is the base SchemaType handlers ($in, $nin, $ne, $eq, $exists, ...) plus $gt/$gte/$lt/$lte and the bitwise operators $bitsAllSet/$bitsAnySet/$bitsAllClear/$bitsAnyClear. Any other operator in a filter object for a Buffer path — e.g. $regex, $mod, $all — reaches the guard.

Source

Thrown at lib/schema/buffer.js:304

  enumerable: false,
  value: $conditionalHandlers
});


/**
 * Casts contents for queries.
 *
 * @param {string} $conditional
 * @param {any} [value]
 * @api private
 */

SchemaBuffer.prototype.castForQuery = function($conditional, val, context) {
  let handler;
  if ($conditional != null) {
    handler = this.$conditionalHandlers[$conditional];
    if (!handler) {
      throw new Error('Can\'t use ' + $conditional + ' with Buffer.');
    }
    return handler.call(this, val);
  }

  let casted;
  try {
    casted = this.applySetters(val, context);
  } catch (err) {
    if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
      err.path = this.$fullPath;
    }
    throw err;
  }
  return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
};

/**
 * Returns this schema type's representation in a JSON schema.

View on GitHub (pinned to 49cdab0136)

Solutions

  1. Change the schema so the value you search with text operators is a String (store hex/base64 alongside) and index that field
  2. Use operators Buffer supports: comparisons ($gt/$lt/...) and bitwise ($bitsAllSet/...); remember $in/$ne/$exists work from the base handlers
  3. In dynamic query builders, whitelist operators per schema type before composing the filter
  4. Catch the Error and surface which path/operator pair was rejected so callers can fix their query

Example fix

// before
Model.find({ dataHash: { $regex: `^${prefix}` } }); // Buffer path

// after
Model.find({ dataHashHex: { $regex: `^${prefix}` } }); // keep a hex String copy of the hash
Defensive patterns

Strategy: validation

Validate before calling

const BUFFER_OPS = new Set(['$gt','$gte','$lt','$lte','$in','$nin','$ne','$eq','$exists','$bitsAllSet','$bitsAnySet','$bitsAllClear','$bitsAnyClear','$not','$cmp','$and','$or']);
function assertBufferOpsSafe(filter) {
  for (const [k, v] of Object.entries(filter ?? {})) {
    if (k.startsWith('$')) continue;
    if (v && typeof v === 'object' && !Array.isArray(v)) {
      for (const op of Object.keys(v)) {
        if (op.startsWith('$') && !BUFFER_OPS.has(op)) throw new Error(`operator ${op} not allowed on ${k}`);
      }
    }
  }
}

Try / catch

try { await Model.find(filter); } catch (err) { if (/Can't use .* with Buffer/.test(err.message)) { throw Object.assign(new Error('unsupported buffer operator'), { status: 400 }); } throw err; }

Prevention

When it happens

Trigger: `Model.find({ dataHash: { $regex: /^abc/ } })` or any filter `{ <bufferPath>: { $<op>: value } }` where $op is not in SchemaBuffer's $conditionalHandlers. Also `Model.find({ buf: { $near: [1, 2] } })` or operator typos like `$regexi`.

Common situations: Reusing a query originally written for a String path against a Buffer path after a schema change; dynamic query builders (search filters, GraphQL resolvers) that apply the same operator set to every field; using text-ish operators on binary hashes.

Related errors


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