Automattic/mongoose · error · CastError
Cast to Int32 failed for value "${value}" (type ${valueType}
Error message
Cast to Int32 failed for value "${value}" (type ${valueType}) at path "${path}" What it means
SchemaInt32.cast converts failures of the Int32 caster (lib/cast/int32.js) into this CastError. Valid input: null/undefined, empty string (→ null), BSON Long, and anything Number() coerces to an integer within [-2147483648, 2147483647]. Arrays, non-integer values (1.5), and out-of-range integers (3000000000, millisecond timestamps) throw.
Source
Thrown at lib/schema/int32.js:193
* @param {object} value
* @param {object} model this value is optional
* @api private
*/
SchemaInt32.prototype.cast = function(value) {
let castInt32;
if (typeof this._castFunction === 'function') {
castInt32 = this._castFunction;
} else if (typeof this.constructor.cast === 'function') {
castInt32 = this.constructor.cast();
} else {
castInt32 = SchemaInt32.cast();
}
try {
return castInt32(value);
} catch (error) {
throw new CastError('Int32', value, this.path, error, this);
}
};
/*!
* ignore
*/
const $conditionalHandlers = {
...SchemaType.prototype.$conditionalHandlers,
$gt: handleSingle,
$gte: handleSingle,
$lt: handleSingle,
$lte: handleSingle,
$bitsAllClear: handleBitwiseOperator,
$bitsAnyClear: handleBitwiseOperator,
$bitsAllSet: handleBitwiseOperator,
$bitsAnySet: handleBitwiseOperator
};View on GitHub (pinned to 49cdab0136)
Solutions
- Use `mongoose.Schema.Types.Long` or plain `Number` for values that can exceed ±2^31; Int32 is only for guaranteed-small integers
- Round before assigning: `doc.count = Math.trunc(v)` and range-check the result
- Validate at the boundary: `Number.isInteger(v) && v >= -2147483648 && v <= 2147483647`
- Store timestamps as `Schema.Types.Date` instead of numeric epochs
Example fix
// before
event.ts = { type: mongoose.Schema.Types.Int32 }; // then: event.ts = Date.now();
// after
event.ts = { type: Date }; // or Schema.Types.Long for epoch millis
event.ts = Date.now(); Defensive patterns
Strategy: type-guard
Validate before calling
const INT32_MIN = -0x80000000, INT32_MAX = 0x7FFFFFFF;
function isInt32(v) {
if (v == null || v === '') return true;
if (Array.isArray(v)) return false;
const n = typeof v === 'number' ? v : Number(v);
return Number.isInteger(n) && n >= INT32_MIN && n <= INT32_MAX;
}
if (!isInt32(req.body.count)) throw new Error('count must be a 32-bit integer'); Type guard
function isInt32Value(v) {
return Number.isInteger(v) && v >= -0x80000000 && v <= 0x7FFFFFFF;
} Try / catch
try { doc.count = v; } catch (err) { if (err.name === 'CastError' && err.kind === 'Int32') { return badRequest(`${err.path} must be an integer in [-2147483648, 2147483647]`); } throw err; } Prevention
- Use Long or Date for epoch millis, never Int32
- Range-check counters that can grow unbounded
- Math.trunc decimals before assigning to Int32 paths
When it happens
Trigger: `doc.count = 1.5` (non-integer), `doc.count = 3000000000` (exceeds 2^31-1), `doc.count = [1]` (array), `doc.count = 'abc'`, or a Long larger than Int32 range. Query side: `{ count: { $gt: 'big' } }`.
Common situations: Counters and view stats overflowing Int32; Date.now() millisecond timestamps stored in an Int32 path (they need Long or Number); user input with decimals; migrating a Number path to Int32 while existing data exceeds the range; negative overflow from signed math.
Related errors
- Query filter must be an object, got an array ${util.inspect(
- Cast to date failed for value "${value}" (type ${valueType})
- Cast to Decimal128 failed for value "${value}" (type ${value
- Cast to Double failed for value "${value}" (type ${valueType
- Cast to Number failed for value "${value}" (type ${valueType
AI-assisted analysis of Automattic/mongoose@49cdab0136 (2026-08-21).
Data as JSON: /api/errors/97958d76fcf56dce.
Report an issue: GitHub.