Skip to content

Conversation

@valeriancure
Copy link

  • Fixes a bug where bigint was serialized as number in relation, losing precision.
  • Native bigserial and bigint types are automatically casted to text.
  • Allows custom types to also be casted via castInRelation: 'text'.
  • Added tests for native and custom types, with one and many relations.

There are probably edge cases not covered, my understanding of drizzle's internals being limited.

Related (pg) : #3267, #813
Related (other dialect) : #1688

@xorraxraxret
Copy link

An easy fix for this, if this never gets merged, is to simply cast your columns with ::text.

Eg.

json_agg_strict(users.id::text)

…om int8)

Fixes a bug where bigint was serialized as number in relation, losing
precision.
Native bigserial and bigint types are automatically casted to string.
Allows custom int8 types to also be casted via `castInRelation: 'text'`.
Added tests for native and custom types, with `one` and `many`
relations.
@valeriancure valeriancure force-pushed the pg-cast-bigint-in-relation branch from 3d8c34c to afea0d9 Compare June 2, 2025 08:44
@jacquesamsel
Copy link

Would love to see this merged!

@sleitor
Copy link

sleitor commented Nov 15, 2025

✅ Confirmed Working - Real Production Testing

We encountered this exact precision loss issue in production with Telegram API accessHash values (19-20 digit bigints exceeding Number.MAX_SAFE_INTEGER).

The Problem

When using nested queries with with: { relation: true }, bigint columns were losing precision:

// Expected value from database
5810142810638157171n

// What we actually got in nested queries
5810142810638156800n  // ❌ Precision loss: 371 in last digits

This happens because the PostgreSQL driver returns a JavaScript Number for bigint columns in JOIN queries, and Number.MAX_SAFE_INTEGER (2^53 - 1) is exceeded, causing silent data corruption.

Test Results with Your Patch

Applied your fix to Drizzle ORM 0.44.7 via patch-package and confirmed it completely solves the issue:

Before Patch:

  • Direct query: 5810142810638157171 ✅ (correct)
  • Nested query: 5810142810638156800 ❌ (precision loss)
  • Raw SQL: 5810142810638157171 ✅ (correct)

After Patch:

  • Direct query: 5810142810638157171
  • Nested query: 5810142810638157171FIXED!
  • Raw SQL: 5810142810638157171

All query types now return identical, correct values! 🎉

Our Implementation

We're using the core concept from this PR with minimal changes:

  1. pg-core/columns/bigint.js: Added validation to detect precision loss
  2. pg-core/dialect.js: Auto-cast PgBigInt64 to TEXT in buildRelationalQueryWithoutPK()
// In json_build_array for nested relations
if (is(field2, Column) && is(field2, PgBigInt64)) {
  return sql`CAST(${field2} AS TEXT)`;
}

Impact

This is a critical data integrity bug affecting any application using:

  • Bigint foreign keys in relations
  • Large integer IDs (Twitter/X snowflake IDs, Telegram IDs, etc.)
  • Any bigint > 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER)

The fix is minimal, focused, and working perfectly in our production environment with real user data.

Request

Please merge this PR! 🙏

We're currently using it via patch-package, but would love to see it in the official release. This bug causes silent data corruption that can be very difficult to detect and debug.

Happy to help with:

  • Additional testing on different PostgreSQL versions
  • Edge case verification
  • Documentation
  • Whatever else is needed to get this merged

Thank you for the work on this fix! 🚀


Tested on:

  • Drizzle ORM: 0.44.7
  • PostgreSQL: Neon Serverless
  • Driver: @neondatabase/serverless + drizzle-orm/neon-http
  • Production data: Telegram API accessHash values (19-20 digit bigints)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants