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
- Change the schema so the value you search with text operators is a String (store hex/base64 alongside) and index that field
- Use operators Buffer supports: comparisons ($gt/$lt/...) and bitwise ($bitsAllSet/...); remember $in/$ne/$exists work from the base handlers
- In dynamic query builders, whitelist operators per schema type before composing the filter
- 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
- Keep a per-type operator whitelist in dynamic query builders
- Store searchable encodings (hex/base64) in String paths for text operators
- Add integration tests for every operator your API exposes
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
- Can't use ${$conditional} with Date.
- Can't use ${conditional} with Number.
- Query filter must be an object, got an array ${util.inspect(
- Cast to number failed for value "${value}" (type ${valueType
- Invalid addFields() argument. Must be an object
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/9af07443fe8c8b8e.
Report an issue: GitHub.