Automattic/mongoose · error · CastError
Cast to number failed for value "${value}" (type ${valueType
Error message
Cast to number failed for value "${value}" (type ${valueType}) at path "${path}" What it means
handleBitwiseOperator (the handler for $bitsAllSet/$bitsAnySet/$bitsAllClear/$bitsAnyClear on Buffer/Int32/Number paths) accepts Buffers, numeric masks, or arrays of bit positions; every non-Buffer entry goes through `_castNumber`, which throws CastError 'number' when `Number(num)` is NaN. So a bitwise filter received a mask value that is not numeric — a garbage string, an object, or an array containing such entries.
Source
Thrown at lib/schema/operators/bitwise.js:33
if (Array.isArray(val)) {
return val.map(function(v) {
return _castNumber(_this.path, v);
});
} else if (Buffer.isBuffer(val)) {
return val;
}
// Assume trying to cast to number
return _castNumber(_this.path, val);
}
/*!
* ignore
*/
function _castNumber(path, num) {
const v = Number(num);
if (isNaN(v)) {
throw new CastError('number', num, path);
}
return v;
}
module.exports = handleBitwiseOperator;
View on GitHub (pinned to 49cdab0136)
Solutions
- Pass integer bitmasks (`{ $bitsAllSet: 0b101 }` = 5) or arrays of bit positions with integers only (`[0, 2]`)
- Validate masks before querying: `Number.isInteger(mask) || (Array.isArray(mask) && mask.every(Number.isInteger))`
- Sanitize config-driven masks at load time with the same check
- Accept Buffer masks if flags are byte-oriented
Example fix
// before
Model.find({ permissions: { $bitsAllSet: req.query.mask } }); // 'admin'
// after
const mask = Number(req.query.mask);
if (!Number.isInteger(mask) || mask < 0) {
return res.status(400).json({ error: 'mask must be an integer' });
}
Model.find({ permissions: { $bitsAllSet: mask } }); Defensive patterns
Strategy: validation
Validate before calling
function isValidBitMask(v) {
if (Buffer.isBuffer(v)) return true;
if (Array.isArray(v)) return v.every(Number.isInteger);
return Number.isInteger(v);
}
if (!isValidBitMask(mask)) throw Object.assign(new Error('mask must be integer or array of integers'), { status: 400 });
Model.find({ flags: { $bitsAllSet: mask } }); Type guard
function isBitMask(v) {
return Buffer.isBuffer(v) || Number.isInteger(v) || (Array.isArray(v) && v.every(Number.isInteger));
} Try / catch
try { await Model.find({ flags: { $bitsAllSet: mask } }); } catch (err) { if (err.name === 'CastError' && err.kind === 'number') { return badRequest('bit mask must be numeric'); } throw err; } Prevention
- Keep bitmasks as integers in config, not free-form strings
- Validate feature-flag masks at config load time
- Document bit-position arrays vs bitmask numbers per endpoint
When it happens
Trigger: `Model.find({ flags: { $bitsAllSet: 'x1' } })` (non-numeric string), `{ flags: { $bitsAllSet: ['a', 'b'] } }` (array with non-numeric bit positions), or an object/undefined leaking in as the mask. Note `Buffer` masks pass through untouched; numbers and numeric strings are fine ('0x1f', '5', 31).
Common situations: Building bitwise feature-flag or permission filters from unvalidated config/user input; passing hex strings with a 0X prefix typo ('0X1F' actually parses — the breakers are values like 'true', '', or objects); mixing up bit-position arrays and bitmask numbers from documentation examples.
Related errors
- Query filter must be an object, got an array ${util.inspect(
- Cast to Array failed for value "${value}" at path "${path}"
- Cast to Object failed for value "${value}" at path "${path}.
- Can't use ${$conditional} with Buffer.
- Can't use ${$conditional} with Date.
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/f2cdaa3fa3f1c7b1.
Report an issue: GitHub.