From 9822ab3a3064e98d0e5d52fcaa50ab7300a8aa68 Mon Sep 17 00:00:00 2001 From: okxint Date: Tue, 21 Jul 2026 12:31:23 +0530 Subject: [PATCH] fix(events): prevent float precision loss in nanosecond timestamp conversion Multiplying milliseconds by 1_000_000 before BigInt conversion loses precision because the result (~1.7e18) exceeds Number.MAX_SAFE_INTEGER. Switch all three call sites to use convertDateToNanoseconds(), which does BigInt(ms) * BigInt(1_000_000) and keeps the arithmetic in BigInt-land throughout. --- .server-changes/fix-bigint-nanosecond-precision.md | 6 ++++++ apps/webapp/app/v3/eventRepository/common.server.ts | 4 ++-- apps/webapp/app/v3/eventRepository/index.server.ts | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 .server-changes/fix-bigint-nanosecond-precision.md diff --git a/.server-changes/fix-bigint-nanosecond-precision.md b/.server-changes/fix-bigint-nanosecond-precision.md new file mode 100644 index 00000000000..2a9f6b9b05a --- /dev/null +++ b/.server-changes/fix-bigint-nanosecond-precision.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: fix +--- + +Timestamp precision is no longer lost when recording nanosecond-resolution span times. Previously, multiplying milliseconds by 1,000,000 in float-land before converting to BigInt produced slightly wrong timestamps for spans and run events. diff --git a/apps/webapp/app/v3/eventRepository/common.server.ts b/apps/webapp/app/v3/eventRepository/common.server.ts index eb8bf7f23ec..137a440c3fd 100644 --- a/apps/webapp/app/v3/eventRepository/common.server.ts +++ b/apps/webapp/app/v3/eventRepository/common.server.ts @@ -25,7 +25,7 @@ export function extractContextFromCarrier(carrier: Record) { } export function getNowInNanoseconds(): bigint { - return BigInt(new Date().getTime() * 1_000_000); + return convertDateToNanoseconds(new Date()); } export function getDateFromNanoseconds(nanoseconds: bigint): Date { @@ -39,7 +39,7 @@ export function calculateDurationFromStart( ) { const $endtime = typeof endTime === "string" ? new Date(endTime) : endTime; - const duration = Number(BigInt($endtime.getTime() * 1_000_000) - startTime); + const duration = Number(convertDateToNanoseconds($endtime) - startTime); if (minimumDuration && duration < minimumDuration) { return minimumDuration; diff --git a/apps/webapp/app/v3/eventRepository/index.server.ts b/apps/webapp/app/v3/eventRepository/index.server.ts index f0687d2a7ce..29b8d948e24 100644 --- a/apps/webapp/app/v3/eventRepository/index.server.ts +++ b/apps/webapp/app/v3/eventRepository/index.server.ts @@ -1,6 +1,7 @@ import { env } from "~/env.server"; import { eventRepository } from "./eventRepository.server"; import { type IEventRepository, type TraceEventOptions } from "./eventRepository.types"; +import { convertDateToNanoseconds } from "./common.server"; import { prisma } from "~/db.server"; import { runStore } from "../runStore.server"; import { controlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.server"; @@ -240,7 +241,7 @@ async function recordRunEvent( runId: foundRun.friendlyId, ...attributes, }, - startTime: BigInt((startTime?.getTime() ?? Date.now()) * 1_000_000), + startTime: convertDateToNanoseconds(startTime ?? new Date()), ...optionsRest, });