sindresorhus/is · error · TypeError

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

Error message

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

What it means

Thrown by `assert.symbol()` (assertSymbol at source/index.ts:1900) when the value is not a primitive `symbol` per `typeof value === 'symbol'`. Strings that look like symbol descriptions, objects, and everything else fail. Used to guarantee a value can serve as a unique, collision-free key.

Source

Thrown at source/index.ts:1902

		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));
	}
}

export function assertTypedArray(value: unknown, message?: string): asserts value is TypedArray {
	if (!isTypedArray(value)) {
		throw new TypeError(message ?? typeErrorMessage('TypedArray', value));

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Pass an actual symbol: `Symbol('name')` or `Symbol.for('name')` instead of a string.
  2. If the symbol must be shared across modules or realms, use the global registry `Symbol.for(key)` so all copies agree.
  3. If the value crossed a serialization boundary, redesign to use a string key there — symbols cannot be serialized.

Example fix

// before
const kind = 'node-kind';
assert.symbol(kind);
// after
const kind = Symbol.for('node-kind');
assert.symbol(kind);
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

function isSymbol(value: unknown): value is symbol {
  return typeof value === 'symbol';
}

Try / catch

try {
  assert.symbol(value);
} catch (error) {
  if (error instanceof TypeError) {
    // a string key or Symbol description was passed instead of the Symbol itself
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling `assert.symbol(value)` with a string (e.g. `'Symbol(id)'` or a plain name where `Symbol('name')` was expected), `undefined`, or the result of serialization — symbols cannot cross JSON, structuredClone, or worker boundaries.

Common situations: Symbols lost across module duplication (two copies of a package each creating their own `Symbol('kind')` — use `Symbol.for()` for a shared registry); values round-tripped through JSON where symbols were silently dropped to `undefined`; confusing well-known symbol names with the symbols themselves.

Related errors


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