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
- Change the normalization entry's type to 'string' for alphanumeric transaction ids
- 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)
- 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
- Default normalization type to string (or omit type) for connector transaction ids
- Remember null coerces to 0 but undefined/NaN strings throw — validate presence too
- BigInt path only engages for finite but unsafe integers, so huge numeric strings are fine
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
- Invalid config: missing path
- Path does not exist: ${config.path}
- Please provide a baseUrl
- Unsupported baseUrl
- Unsupported keyIdType: ${keyIdType}
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/182908d54f0db247.
Report an issue: GitHub.