Skip to content

OTLP nanosecond timestamp overflow in webapp event repository #3292

Open

Description

@nicktrn

Several places in the webapp multiply epoch milliseconds by 1,000,000 before converting to BigInt, which causes IEEE 754 precision loss (~256ns errors in ~0.2% of cases). The result exceeds Number.MAX_SAFE_INTEGER (~9e15) since epoch-ms * 1e6 is ~1.7e18.

The correct pattern is BigInt(ms) * BigInt(1_000_000) (multiplication after BigInt conversion). This already exists in convertDateToNanoseconds() in the same file - the buggy functions just didn't use it.

Affected locations:

  1. apps/webapp/app/v3/eventRepository/common.server.ts:24 - getNowInNanoseconds()

    // Bug: multiplication in float-land
    return BigInt(new Date().getTime() * 1_000_000);
    // Fix:
    return BigInt(new Date().getTime()) * BigInt(1_000_000);
  2. apps/webapp/app/v3/eventRepository/common.server.ts:38 - calculateDurationFromStart()

    // Bug:
    const duration = Number(BigInt($endtime.getTime() * 1_000_000) - startTime);
    // Fix:
    const duration = Number(BigInt($endtime.getTime()) * BigInt(1_000_000) - startTime);
  3. apps/webapp/app/v3/eventRepository/index.server.ts:217 - recordRunDebugLog()

  4. apps/webapp/app/v3/runEngineHandlers.server.ts:431 - retry event recording

Impact: Low. The errors are +-256 nanoseconds, which is unlikely to cause visible issues. But it's an easy fix and prevents any edge cases with span ordering.

Context: Found during compute workload manager PR review (#3114). The supervisor's msToNano() was fixed in that PR using a split approach that also preserves sub-ms precision from performance.now() arithmetic.

Linear: TRI-8269

Activity

  1. added a commit that references this issue on Mar 29, 2026
    8176a6b
  2. added a commit that references this issue on Apr 12, 2026
    26de74f
  3. added 2 commits that reference this issue on Apr 15, 2026
    170c1f3
    65e5e38
  4. added a commit that references this issue on Apr 15, 2026
    c10ca6d
  5. aayushbaluni commented on Apr 15, 2026

    @aayushbaluni

    I've submitted PR #3381 fixing all instances of the BigInt overflow pattern, including the one at runEngineHandlers.server.ts:432 that was missed in the previous PR #3378. However, the PR was auto-closed because I need to be vouched as a contributor. Could a maintainer please help with that?

  6. added a commit that references this issue on Jun 17, 2026
    8a26457
  7. AkhilTrivediX commented on Aug 4, 2026

    @AkhilTrivediX

    Hi! I've written a fix for this precision loss issue and submitted PR #4499. However, the PR was automatically closed because I am not on the vouched contributors list yet. Could a maintainer please vouch for me so I can reopen the PR? Thank you!

  8. robinthedev-a11y commented on Sep 9, 2026

    @robinthedev-a11y

    Hi — noticed this is still open and the buggy BigInt(ms * 1e6) pattern is still on main in eventRepository/common.server.ts. Prior spam PRs were closed; no open claim.

    Happy to ship a clean TS fix: switch all ms→ns sites to BigInt(ms) * BigInt(1_000_000) (matching convertDateToNanoseconds), plus a small regression test.

    If useful, could you /bounty $125 on this issue via Algora? I’ll exclusive-PR within 48–72h as @robinthedev-a11y.

    Happy to adjust amount/scope. Thanks for the OSS + past Algora payouts.

  9. bilalhusain-dev commented on Oct 12, 2026

    @bilalhusain-dev

    🔍 Root Cause Analysis & Complete Fix across all 4 Call Sites

    Hey team,

    I investigated the OTLP nanosecond timestamp precision loss on the current main branch.

    Why this happens

    In JavaScript, standard numbers are IEEE 754 64-bit floats with Number.MAX_SAFE_INTEGER = 9,007,199,254,740,991 (9e15). An epoch millisecond timestamp (1.78e12) multiplied by 1_000_000 produces ~1.78e18, which far exceeds Number.MAX_SAFE_INTEGER. Multiplying prior to BigInt conversion causes truncation/rounding errors (±256ns) in ~0.2% of timestamps.

    The safe pattern (already used in convertDateToNanoseconds) is to cast to BigInt first:
    BigInt(ms) * BigInt(1_000_000)


    Proposed Fix (All 4 Affected Locations)

    diff --git a/apps/webapp/app/v3/eventRepository/common.server.ts b/apps/webapp/app/v3/eventRepository/common.server.ts
    index e23a45b..b89c102 100644
    --- a/apps/webapp/app/v3/eventRepository/common.server.ts
    +++ b/apps/webapp/app/v3/eventRepository/common.server.ts
    @@ -24,3 +24,3 @@ export function getNowInNanoseconds(): bigint {
    -  return BigInt(new Date().getTime() * 1_000_000);
    +  return BigInt(new Date().getTime()) * BigInt(1_000_000);
     }
    @@ -38,3 +38,3 @@ export function calculateDurationFromStart(
    -  const duration = Number(BigInt($endtime.getTime() * 1_000_000) - startTime);
    +  const duration = Number(BigInt($endtime.getTime()) * BigInt(1_000_000) - startTime);
    
    diff --git a/apps/webapp/app/v3/eventRepository/index.server.ts b/apps/webapp/app/v3/eventRepository/index.server.ts
    index c45d12a..d78e341 100644
    --- a/apps/webapp/app/v3/eventRepository/index.server.ts
    +++ b/apps/webapp/app/v3/eventRepository/index.server.ts
    @@ -211,3 +211,3 @@ export async function recordRunDebugLog({
    -      startTime: BigInt((startTime?.getTime() ?? Date.now()) * 1_000_000),
    +      startTime: BigInt(startTime?.getTime() ?? Date.now()) * BigInt(1_000_000),
    
    diff --git a/apps/webapp/app/v3/runEngineHandlers.server.ts b/apps/webapp/app/v3/runEngineHandlers.server.ts
    index a12bc34..f56ef89 100644
    --- a/apps/webapp/app/v3/runEngineHandlers.server.ts
    +++ b/apps/webapp/app/v3/runEngineHandlers.server.ts
    @@ -560,3 +560,3 @@ export async function recordRetryEvent({
    -          startTime: BigInt(time.getTime() * 1000000),
    +          startTime: BigInt(time.getTime()) * BigInt(1_000_000),
  10. added a commit that references this issue on Oct 14, 2026
    33f68e7
  11. oziass commented on Oct 14, 2026

    @oziass

    /attempt #3292

    Hey team — I put together a fix and colocated unit tests for this in PR #5027 (auto-closed by the vouch bot as a first-time contributor here):

    • Updated getNowInNanoseconds and calculateDurationFromStart in common.server.ts to use convertDateToNanoseconds so epoch ms is converted to BigInt before multiplying by 1_000_000.
    • Updated the remaining BigInt(ms * 1_000_000) sites in index.server.ts and
      unEngineHandlers.server.ts to BigInt(ms) * BigInt(1_000_000).
    • Added real-clock unit tests in �pps/webapp/app/v3/eventRepository/common.server.test.ts (and resolved both Devin review notes in 33f68e7).

    Could a maintainer vouch @oziass so #5027 can be reopened? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions