sindresorhus/is · error · TypeError

Expected value which is not `${description}`, received value

Error message

Expected value which is not `${description}`, received value of type `${is(value)}`.

What it means

Thrown by negative assertions created via `createAssertNot` (source/index.ts:1168) — e.g. `assertNotUndefined`, `assertNotNull`, `assertNotString` — when the value *does* match the forbidden type. The message from `typeErrorMessageNot` names the forbidden description and the actual detected type. This is the assertion working as designed: the value violated the 'must not be X' contract.

Source

Thrown at source/index.ts:1171

type NotAssert = {
	undefined: NotAssertion<undefined, UnknownNotPrimitive<undefined>>;
	// eslint-disable-next-line @typescript-eslint/no-restricted-types
	null: NotAssertion<null, UnknownNotPrimitive<null>>;
	// eslint-disable-next-line @typescript-eslint/no-restricted-types
	nullOrUndefined: NotAssertion<null | undefined, UnknownNotPrimitive<null | undefined>>;
	string: NotAssertion<string, UnknownNotPrimitive<string>>;
	boolean: NotAssertion<boolean, UnknownNotPrimitive<boolean>>;
	symbol: NotAssertion<symbol, UnknownNotPrimitive<symbol>>;
	bigint: NotAssertion<bigint, UnknownNotPrimitive<bigint>>;
	// eslint-disable-next-line @typescript-eslint/no-restricted-types
	primitive: NotAssertion<Primitive, object>;
};

// Negative assertions are limited to types where the assertion rejects every TypeScript value assignable to the forbidden type. Structural object types such as `Map`, `Set`, `Date`, and `Array` are excluded because TypeScript accepts shape-compatible mocks while the runtime checks use object brands, so `Exclude` would narrow values that can pass the negative assertion.
function createAssertNot<Forbidden, UnknownResult = unknown>(predicate: Predicate, description: AssertionTypeDescription): NotAssertion<Forbidden, UnknownResult> {
	return <Value>(value: Value, message?: string): asserts value is NotAssertionResult<Value, Forbidden, UnknownResult> => {
		if (predicate(value)) {
			throw new TypeError(message ?? typeErrorMessageNot(description, value));
		}
	};
}

export const assertNotUndefined: NotAssertion<undefined, UnknownNotPrimitive<undefined>> = createAssertNot<undefined, UnknownNotPrimitive<undefined>>(isUndefined, 'undefined');
// eslint-disable-next-line @typescript-eslint/no-restricted-types
export const assertNotNull: NotAssertion<null, UnknownNotPrimitive<null>> = createAssertNot<null, UnknownNotPrimitive<null>>(isNull, 'null');
// eslint-disable-next-line @typescript-eslint/no-restricted-types
export const assertNotNullOrUndefined: NotAssertion<null | undefined, UnknownNotPrimitive<null | undefined>>
	// eslint-disable-next-line @typescript-eslint/no-restricted-types
	= createAssertNot<null | undefined, UnknownNotPrimitive<null | undefined>>(isNullOrUndefined, 'null or undefined');
export const assertNotString: NotAssertion<string, UnknownNotPrimitive<string>> = createAssertNot<string, UnknownNotPrimitive<string>>(isString, 'string');
export const assertNotBoolean: NotAssertion<boolean, UnknownNotPrimitive<boolean>> = createAssertNot<boolean, UnknownNotPrimitive<boolean>>(isBoolean, 'boolean');
export const assertNotSymbol: NotAssertion<symbol, UnknownNotPrimitive<symbol>> = createAssertNot<symbol, UnknownNotPrimitive<symbol>>(isSymbol, 'symbol');
export const assertNotBigint: NotAssertion<bigint, UnknownNotPrimitive<bigint>> = createAssertNot<bigint, UnknownNotPrimitive<bigint>>(isBigint, 'bigint');
export const assertNotPrimitive: NotAssertion<Primitive, object> = createAssertNot<Primitive, object>(isPrimitive, 'primitive'); // eslint-disable-line @typescript-eslint/no-restricted-types

// We intentionally do not support `assert.not(is.undefined, value)`. TypeScript cannot derive safe complement types from arbitrary predicates, and many predicates here are refinements (for example, `is.number` rejects `NaN`). Explicit methods keep runtime checks and type narrowing aligned.

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Treat this as a data problem, not a library problem: trace why the value is the forbidden type at that point (missing config, absent field, uninitialized state) and fix the source.
  2. If the forbidden type is legitimately possible, replace the assertion with a conditional branch that handles that case.
  3. Pass a custom `message` argument to the assertion so failures identify which value and context failed.

Example fix

// before
const url = process.env.API_URL;
assertNotUndefined(url); // throws when env var unset

// after
const url = process.env.API_URL;
assertNotUndefined(url, 'API_URL environment variable must be set');
Defensive patterns

Strategy: try-catch

Validate before calling

if (is.nan(value)) {
  // handle the disallowed type yourself before calling assert.not.*
}

Type guard

function isNot<T>(predicate: (v: unknown) => boolean, value: unknown): boolean {
  return !predicate(value);
}

Try / catch

try {
  assert.not.undefined(value);
} catch (error) {
  if (error instanceof TypeError) {
    // value WAS of the disallowed type — report/reject at the boundary
    return handleInvalidInput(error.message);
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling `assertNotUndefined(value)` when `value` is undefined, `assertNotNull(x)` when `x` is null, `assertNotString`/`assertNotBoolean`/`assertNotSymbol`/`assertNotBigint`/`assertNotPrimitive` when the value is of that exact forbidden type.

Common situations: Optional data (missing object property, unset env var, `Map.get` miss) flowing into a code path that asserts presence with `assertNotUndefined`/`assertNotNull`; API responses with null fields; race conditions where a value isn't initialized yet.

Related errors


AI-assisted analysis of sindresorhus/is@7821031c66 (2026-07-31). Data as JSON: /data/errors/ed0a0a0c48aafb68.json. Report an issue: GitHub ↗.