sindresorhus/is · error · TypeError
Expected value which is `plain object`, received value of ty
Error message
Expected value which is `plain object`, received value of type `${is(value)}`. What it means
Thrown by `assert.plainObject()` when the value is not a plain object — one created by `{}`, `new Object()`, or `Object.create(null)`. `isPlainObject` rejects arrays, class instances, Maps, Dates, functions, and primitives, which the looser `assert.object()` would accept. It narrows to `Record<PropertyKey, Value>` for safe key-value access.
Source
Thrown at source/index.ts:1836
throw new TypeError(message ?? typeErrorMessage('Object', value));
}
}
export function assertObservable(value: unknown, message?: string): asserts value is ObservableLike {
if (!isObservable(value)) {
throw new TypeError(message ?? typeErrorMessage('Observable', value));
}
}
export function assertOddInteger(value: number, message?: string): asserts value is number {
if (!isOddInteger(value)) {
throw new TypeError(message ?? typeErrorMessage('odd integer', value));
}
}
export function assertPlainObject<Value = unknown>(value: unknown, message?: string): asserts value is Record<PropertyKey, Value> {
if (!isPlainObject(value)) {
throw new TypeError(message ?? typeErrorMessage('plain object', value));
}
}
export function assertPositiveInteger(value: unknown, message?: string): asserts value is number {
if (!isPositiveInteger(value)) {
throw new TypeError(message ?? typeErrorMessage('positive integer', value));
}
}
export function assertPositiveNumber(value: unknown, message?: string): asserts value is number {
if (!isPositiveNumber(value)) {
throw new TypeError(message ?? typeErrorMessage('positive number', value));
}
}
export function assertPrimitive(value: unknown, message?: string): asserts value is Primitive {
if (!isPrimitive(value)) {
throw new TypeError(message ?? typeErrorMessage('primitive', value));View on GitHub ↗ (pinned to 7821031c66)
Solutions
- If the value is an array of entries or a Map, convert with `Object.fromEntries(value)` before asserting.
- If class instances should be accepted, use the looser `assert.object()` instead.
- Spread instances into plain objects at the boundary: `{...instance}` — noting this drops methods and prototype.
- Check the API contract — a top-level JSON array vs object mismatch means the producer changed shape.
Example fix
// before const options = new Map([['depth', 2]]); assert.plainObject(options); // throws: received 'Map' // after const options = Object.fromEntries(new Map([['depth', 2]])); assert.plainObject(options);
Defensive patterns
Strategy: type-guard
Validate before calling
const proto = value === null || typeof value !== 'object' ? undefined : Object.getPrototypeOf(value);
if (typeof value !== 'object' || value === null || (proto !== null && proto !== Object.prototype)) {
throw new TypeError('Expected a plain object (created by {} or Object.create(null))');
} Type guard
function isPlainObject(value: unknown): value is Record<string, unknown> {
if (typeof value !== 'object' || value === null) return false;
const proto = Object.getPrototypeOf(value);
return proto === null || proto === Object.prototype;
} Try / catch
try {
ow(value, ow.object.plain);
} catch (error) {
if (error instanceof ArgumentError) {
throw new TypeError(`Options must be a plain object literal: ${error.message}`);
}
throw error;
} Prevention
- Class instances, Maps, arrays, and Dates are objects but not plain objects — spread into a literal ({...instance}) if only data is needed
- Objects crossing realm boundaries (iframes, vm, some structuredClone paths) can fail prototype identity checks
- Pass options as object literals at the call site rather than reusing framework-constructed objects
- JSON.parse output is plain and safe for plain-object parameters
When it happens
Trigger: Calling `assert.plainObject(value)` with an array (a common surprise — arrays are objects but not plain), a class instance, a Map, null, undefined, or a value deserialized into a custom prototype.
Common situations: API returning a JSON array when an object was expected (or vice versa); passing a class-based model/ORM entity where a plain options bag is expected; structuredClone or cross-realm objects with unexpected prototypes; a Map used as a dictionary instead of a plain object.
Related errors
- Expected value which is `number`, received value of type `${
- Expected value which is `string with a number`, received val
- Expected value which is `Object`, received value of type `${
- Expected value which is `primitive`, received value of type
- Expected value which is `non-empty array`, received value of
AI-assisted analysis of sindresorhus/is@7821031c66 (2026-07-31).
Data as JSON: /data/errors/457b7d4d748b39a5.json.
Report an issue: GitHub ↗.