sindresorhus/is · error · TypeError

Expected value which is `string`, received value of type `${

Error message

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

What it means

Thrown by `assert.string()` (assertString at source/index.ts:1894) when `isString` rejects the value — only primitive strings pass. Numbers, `null`, `undefined`, and even boxed `new String('x')` objects fail. It is one of the most frequently used assertions in @sindresorhus/is for validating function arguments at trust boundaries.

Source

Thrown at source/index.ts:1896

		throw new TypeError(message ?? typeErrorMessage('safe integer', value));
	}
}

export function assertSet<T = unknown>(value: unknown, message?: string): asserts value is Set<T> {
	if (!isSet(value)) {
		throw new TypeError(message ?? typeErrorMessage('Set', value));
	}
}

export function assertSharedArrayBuffer(value: unknown, message?: string): asserts value is SharedArrayBuffer {
	if (!isSharedArrayBuffer(value)) {
		throw new TypeError(message ?? typeErrorMessage('SharedArrayBuffer', value));
	}
}

export function assertString(value: unknown, message?: string): asserts value is string {
	if (!isString(value)) {
		throw new TypeError(message ?? typeErrorMessage('string', value));
	}
}

export function assertSymbol(value: unknown, message?: string): asserts value is symbol {
	if (!isSymbol(value)) {
		throw new TypeError(message ?? typeErrorMessage('symbol', value));
	}
}

export function assertTruthy<T>(value: T | Falsy, message?: string): asserts value is T {
	if (!isTruthy(value)) {
		throw new TypeError(message ?? typeErrorMessage('truthy', value));
	}
}

export function assertTupleLike<T extends Array<TypeGuard<unknown>>>(value: unknown, guards: [...T], message?: string): asserts value is ResolveTypesOfTypeGuardsTuple<T> {
	if (!isTupleLike(value, guards)) {
		throw new TypeError(message ?? typeErrorMessage('tuple-like', value));

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Trace the value to its source and ensure it is set — for env vars, define the variable or fail fast at startup with a named error.
  2. Convert intentionally non-string values explicitly: `String(value)` or `buffer.toString('utf8')`.
  3. For optional values, branch with `is.string(value)` or use a default before asserting.

Example fix

// before
const token = process.env.API_TOKEN;
assert.string(token); // throws when env var unset
// after
const token = process.env.API_TOKEN;
if (token === undefined) {
	throw new Error('API_TOKEN environment variable is required');
}
assert.string(token);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof value !== 'string') {
  throw new TypeError(`Expected a string, got ${typeof value}`);
}

Type guard

function isString(value: unknown): value is string {
  return typeof value === 'string';
}

Try / catch

try {
  assert.string(value);
} catch (error) {
  if (error instanceof TypeError) {
    // common culprits: undefined/null from optional fields, numbers, String objects
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling `assert.string(value)` with `undefined` from a missing property or optional parameter, a number (e.g. an ID kept numeric), `null` from an API, or a Buffer that was expected to be decoded.

Common situations: Environment variables absent in a deployment (`process.env.X` is `undefined`); numeric values from JSON where the schema changed; Buffers from `fs.readFile` without an encoding argument; template inputs passed through untyped layers.

Related errors


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