sindresorhus/is · error · TypeError

Expected value which is `non-negative integer`, received val

Error message

Expected value which is `non-negative integer`, received value of type `${is(value)}`.

What it means

Thrown by `assertNonNegativeInteger()` (source/index.ts:1777) when the value is not an integer >= 0. It rejects negative integers, non-integer numbers (1.5), `NaN`, `Infinity`, numeric strings like `'3'`, and BigInts. On success TypeScript narrows the value to `number`.

Source

Thrown at source/index.ts:1779

		throw new TypeError(message ?? typeErrorMessage('non-empty set', value));
	}
}

export function assertNonEmptyString(value: unknown, message?: string): asserts value is string {
	if (!isNonEmptyString(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-empty string', value));
	}
}

export function assertNonEmptyStringAndNotWhitespace(value: unknown, message?: string): asserts value is string {
	if (!isNonEmptyStringAndNotWhitespace(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-empty string and not whitespace', value));
	}
}

export function assertNonNegativeInteger(value: unknown, message?: string): asserts value is number {
	if (!isNonNegativeInteger(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-negative integer', value));
	}
}

export function assertNonNegativeNumber(value: unknown, message?: string): asserts value is number {
	if (!isNonNegativeNumber(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-negative number', value));
	}
}

// eslint-disable-next-line @typescript-eslint/no-restricted-types
export function assertNull(value: unknown, message?: string): asserts value is null {
	if (!isNull(value)) {
		throw new TypeError(message ?? typeErrorMessage('null', value));
	}
}

// eslint-disable-next-line @typescript-eslint/no-restricted-types
export function assertNullOrUndefined(value: unknown, message?: string): asserts value is null | undefined {

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Parse string inputs first: `Number.parseInt(raw, 10)`, then assert.
  2. Check for the `-1` not-found sentinel before using an index from `indexOf`/`findIndex`.
  3. Use `Math.floor`/`Math.round` deliberately if a fractional intermediate value is expected.
  4. Guard arithmetic that can yield NaN (e.g. dividing by zero-length collections).

Example fix

// before
const page = req.query.page;
assert.nonNegativeInteger(page); // '2' is a string — throws
// after
const page = Number.parseInt(req.query.page ?? '0', 10);
assert.nonNegativeInteger(page);
Defensive patterns

Strategy: validation

Validate before calling

if (Number.isInteger(value) && value >= 0) {
  assert.nonNegativeInteger(value);
}

Type guard

function isNonNegativeInteger(v: unknown): v is number {
  return typeof v === 'number' && Number.isInteger(v) && v >= 0;
}

Try / catch

try {
  assert.nonNegativeInteger(index);
} catch (error) {
  if (error instanceof TypeError) {
    // index is negative, fractional, NaN, or not a number — validate the arithmetic that produced it
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling `assert.nonNegativeInteger(value)` with `-1` (common sentinel from `indexOf`-style APIs), a float from a division or average, `NaN` from failed arithmetic, or an unparsed string like `'42'` from query params or env vars.

Common situations: Passing `array.indexOf(x)` results directly (returns -1 on miss); counts or indexes computed with division; HTTP query/route params and env vars used without `Number.parseInt`; off-by-one decrements driving a counter below zero.

Related errors


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