juspay/hyperswitch · error · Error

Cannot coerce "${value}" to number

Error message

Cannot coerce "${value}" to number

What it means

Thrown by coerceValue in Payment/Utils.js when config.type is 'number' and Number(value) is not finite. The coercion supports string and number types for webhook normalization (returning BigInt when the number exceeds the safe-integer range), so any value that cannot parse as a number — 'txn_123', undefined, 'abc' — throws with the offending value quoted.

Source

Thrown at cypress-tests/cypress/e2e/configs/Payment/Utils.js:867

  // Coerce value based on expected type
  const normalizedconnectorTransactionID = coerceValue(
    connectorTransactionID,
    config.type
  );

  target[finalKey] = normalizedconnectorTransactionID;
}

function coerceValue(value, type) {
  switch (type) {
    case "string":
      return String(value);

    case "number": {
      const num = Number(value);
      if (!Number.isFinite(num)) {
        throw new Error(`Cannot coerce "${value}" to number`);
      }
      if (!Number.isSafeInteger(num)) {
        return BigInt(value);
      }
      return num;
    }

    default:
      return value;
  }
}

export function stringifyWithBigInt(obj) {
  return JSON.stringify(obj, (_, value) =>
    typeof value === "bigint" ? `__bigint__${value}` : value
  ).replace(/"__bigint__(\d+)"/g, "$1");
}

View on GitHub (pinned to 9b8b89dc37)

Solutions

  1. Change the normalization entry's type to 'string' for alphanumeric transaction ids
  2. If the value should be numeric, fix the source of the value so it parses (e.g. use the numeric part or ensure the field exists)
  3. Remove the type property entirely — the default branch returns the value unchanged, which is right for opaque ids

Example fix

// before
setNormalizedValue(webhookBody, { path: 'data.body.id', type: 'number' }, 'pay_123ABC');
// throws: Cannot coerce "pay_123ABC" to number

// after
setNormalizedValue(webhookBody, { path: 'data.body.id', type: 'string' }, 'pay_123ABC');
Defensive patterns

Strategy: type-guard

Validate before calling

// Only declare type 'number' when the id really is numeric
function looksNumeric(v) {
  return v !== undefined && v !== null && Number.isFinite(Number(v));
}
if (config.type === 'number' && !looksNumeric(connectorTransactionID)) {
  config = { ...config, type: 'string' }; // opaque ids stay strings
}

Type guard

/** @param {unknown} v @returns {v is string | number} */
function isCoercibleToNumber(v) {
  if (v === null || v === undefined) return false;
  return Number.isFinite(Number(v));
}

Prevention

When it happens

Trigger: A normalization entry { type: 'number' } receives a connector transaction id that is alphanumeric ('pay_123ABC') or undefined; Number('pay_123ABC') is NaN, so Number.isFinite fails and the error names the value.

Common situations: Connector ids that look numeric for one connector (Stripe 'pi_...' never is) inspire a 'number' type; the txn id field is optional and missing in some webhook variants; config copied from a connector with integer ids to one with prefixed ids.

Related errors


AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16). Data as JSON: /api/errors/182908d54f0db247. Report an issue: GitHub.