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

  1. Pass integer bitmasks (`{ $bitsAllSet: 0b101 }` = 5) or arrays of bit positions with integers only (`[0, 2]`)
  2. Validate masks before querying: `Number.isInteger(mask) || (Array.isArray(mask) && mask.every(Number.isInteger))`
  3. Sanitize config-driven masks at load time with the same check
  4. 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

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


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