zloirock/core-js · error · TypeError

Cannot convert a Symbol value to a number

Error message

Cannot convert a Symbol value to a number

What it means

core-js's Number constructor implementation calls ToNumber/ToNumeric, which first converts the argument via ToPrimitive. If the result is still a Symbol, the spec forbids numeric conversion, so core-js throws a TypeError instead of silently producing NaN. This polyfill path runs when the environment's native Number coercion is patched or insufficient.

Source

Thrown at packages/core-js/modules/es.number.constructor.js:41

var PureNumberNamespace = path[NUMBER];
var NumberPrototype = NativeNumber.prototype;
var TypeError = globalThis.TypeError;
var stringSlice = uncurryThis(''.slice);
var charCodeAt = uncurryThis(''.charCodeAt);

// `ToNumeric` abstract operation
// https://tc39.es/ecma262/#sec-tonumeric
var toNumeric = function (value) {
  var primValue = toPrimitive(value, 'number');
  return typeof primValue == 'bigint' ? primValue : toNumber(primValue);
};

// `ToNumber` abstract operation
// https://tc39.es/ecma262/#sec-tonumber
var toNumber = function (argument) {
  var it = toPrimitive(argument, 'number');
  var first, third, radix, maxCode, digits, length, index, code;
  if (isSymbol(it)) throw new TypeError('Cannot convert a Symbol value to a number');
  if (typeof it == 'string' && it.length > 2) {
    it = trim(it);
    first = charCodeAt(it, 0);
    if (first === 43 || first === 45) {
      third = charCodeAt(it, 2);
      if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
    } else if (first === 48) {
      switch (charCodeAt(it, 1)) {
        // fast equal of /^0b[01]+$/i
        case 66:
        case 98:
          radix = 2;
          maxCode = 49;
          break;
        // fast equal of /^0o[0-7]+$/i
        case 79:
        case 111:
          radix = 8;

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Remove the numeric coercion of the Symbol; use the underlying primitive value instead (store the actual id alongside the Symbol).
  2. Use Symbol.keyFor or the symbol's registered key to look up a numeric value rather than coercing the symbol itself.
  3. Add a type check (typeof v === 'symbol') before calling Number() and handle it explicitly.
  4. Ensure you're not accidentally passing the Symbol object returned by Object.getOwnPropertySymbols instead of the data value.
  5. If relying on polyfill behavior, upgrade core-js — newer versions keep spec-compliant coercion messages and paths.

Example fix

// before
const key = getProp(obj); // may be a Symbol
const id = Number(key); // TypeError
// after
const key = getProp(obj);
const id = typeof key === 'symbol' ? null : Number(key);
Defensive patterns

Strategy: type-guard

Validate before calling

function assertNotSymbol(v) { if (typeof v === 'symbol') throw new TypeError('Cannot coerce Symbol to number'); }
assertNotSymbol(value); const n = Number(value);

Type guard

function isSymbol(v) { return typeof v === 'symbol'; }
// usage: if (!isSymbol(v)) { Number(v) }

Try / catch

try {
  const n = Number(value);
} catch (e) {
  if (e instanceof TypeError && /Symbol/.test(e.message)) {
    // handle symbol case: use alternate key/lookup
  } else throw e;
}

Prevention

When it happens

Trigger: Calling new Number(sym) or Number(sym) where sym is a Symbol; any polyfilled numeric coercion (parseInt, parseFloat, +sym, Math.* via Number paths) receiving a Symbol; BigInt()-like polyfill paths using toNumeric with a Symbol argument.

Common situations: Unwrapping a Symbol-keyed value or a library sentinel (e.g. a private-field Symbol from a dependency) and passing it to Number(); arithmetic on mixed values where one operand is a Symbol; deserializing JSON-like data that contained a Symbol after a library upgrade replaced string ids with Symbols.

Related errors


AI-assisted analysis of zloirock/core-js@84e45fba09 (2026-08-30). Data as JSON: /api/errors/fbd37c7d0e8f05fc. Report an issue: GitHub.