January 20, 2026 · backend
Prisma Decimal is not a number: the NaN bug that reached production
Money code has no tolerance for surprises, so when PlayZeet's bet-settlement job
started writing amount: NaN, it went straight to the top of the list.
The trap
Prisma returns Decimal objects for decimal columns, not native numbers. The
moment you do arithmetic like a + b on two Decimal values — or mix a
Decimal with a number — you get results that silently coerce to NaN
instead of the value you expected.
The fix
Normalise at the boundary. The instant a Decimal leaves the database layer,
convert it explicitly, and never compare Decimal instances with ===.
import { Prisma } from "@prisma/client";
const toNum = (d: Prisma.Decimal | number) =>
typeof d === "number" ? d : d.toNumber();
const total = toNum(bet.stake) + toNum(bet.bonus);
The lesson: treat the ORM's return types as a contract, not a formality — especially when real money is on the line.