fix(meshcore): widen neighbor_info timestamp columns to BIGINT (int32 overflow)#3602
Conversation
… overflow)
The meshcore_neighbor_info table (migration 073) declared its `timestamp`
and `createdAt` columns as 32-bit INTEGER on PostgreSQL and INT on MySQL.
Both columns store millisecond-epoch values written via `Date.now()` in
MeshCoreRepository.insertNeighborsBatch (e.g. 1781969045993), which overflow
signed 32-bit integers (max 2,147,483,647).
Production PostgreSQL deployments crashed in MeshCoreRepository.getNeighbors
("Error fetching MeshCore neighbors"):
DrizzleQueryError: Failed query: select ... from "meshcore_neighbor_info"
where ("sourceId" in ($1) and "timestamp" >= $2) order by "timestamp" desc
cause: error: value "1781969045993" is out of range for type integer
(code 22003, pg_strtoint32_safe, numutils.c)
SQLite was unaffected (its INTEGER is 64-bit / dynamically typed).
Changes:
- src/db/schema/meshcoreNeighbors.ts: PG `timestamp`/`createdAt` -> pgBigint
(mode 'number'); MySQL `timestamp`/`createdAt` -> myBigint (mode 'number').
Matches the sibling meshcore_messages / meshcore_nodes / meshcore_packet_log
ms-epoch convention. `lastHeardSecs` (seconds-ago, small int) left as-is.
- src/server/migrations/095_meshcore_neighbor_timestamp_bigint.ts: idempotent
ALTER ... TYPE BIGINT (PG) / MODIFY ... BIGINT NOT NULL (MySQL), guarded by
information_schema checks; SQLite no-op.
- Registered migration 095; bumped migrations.test.ts count to 95.
mode:'number' keeps reads as JS numbers, so no read-site Number() coercion
is required (consistent with meshcore_packet_log).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
|
Claude finished @Yeraze's task —— View job PR Review: fix(meshcore): widen neighbor_info timestamp columns to BIGINT
Overall: LGTM — This is a clean, well-targeted bug fix. The root cause diagnosis is correct and the fix is minimal and surgical. Schema (
|
…p-bigint # Conflicts: # src/db/migrations.test.ts # src/db/migrations.ts
|
Claude finished @Yeraze's task —— View job PR Review: fix(meshcore): widen neighbor_info timestamp columns to BIGINT
Overall: LGTM — This is a clean, well-targeted bug fix. The root cause diagnosis is correct and the fix is minimal and surgical. Note: The PR description references migration Schema (
|
Bump version to 4.11.3 across all five version files and document the changes merged since 4.11.2 in the changelog. Features: - Dead Drop / Mailbox auto-responder (#3538) - MeshCore node favoriting (#3588) - FEM LNA Mode LoRa config on Device Config + Remote Admin (#3599) - MeshCore CLI bundled in the Docker image (#3587) Bug fixes: - meshcore_neighbor_info timestamp BIGINT — PG/MySQL int32 overflow crash (#3602) - downlink/uplinkEnabled proto3 boolean elision revert (#3594) - Position-history SNR for directly-heard (0-hop) nodes (#3590) - MeshCore auto-ack {SNR}/{ROUTE} tokens intermittently blank (#3589) - macOS x64 DMG re2.node arch (Intel Mac crash) (#3603) - Mesh request endpoints return 503 when disconnected (#3596) Also refreshes the CLAUDE.md version header and migration count (96). Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
A production PostgreSQL deployment crashes in
MeshCoreRepository.getNeighbors(surfaced as "Error fetching MeshCore neighbors" viameshcoreRoutes.ts):Root cause
The
meshcore_neighbor_infotable (created in migration 073) declared itstimestampandcreatedAtcolumns as 32-bitINTEGERon PostgreSQL andINTon MySQL. Both columns store millisecond-epoch values written viaDate.now()inMeshCoreRepository.insertNeighborsBatch(e.g.1781969045993), which overflows the signed 32-bit max of2,147,483,647.SQLite was unaffected because its
INTEGERis 64-bit / dynamically typed. This is the same int32-overflow class documented in CLAUDE.md ("Node IDs / packet IDs are BIGINT in PostgreSQL/MySQL") — ms timestamps share the defect.This table was the lone offender: the sibling
meshcore_messages,meshcore_nodes, andmeshcore_packet_logtables already usebigint(..., { mode: 'number' })for their ms-epoch columns. A full audit of every PGpgInteger/MySQLmyIntcolumn with a timestamp-shaped name confirmed no other ms-epoch columns remain mis-typed.Columns changed
meshcore_neighbor_infotimestampinteger/intbigint/bigintmeshcore_neighbor_infocreatedAtinteger/intbigint/bigintDeliberately left as
int:lastHeardSecs(small "seconds-ago" value, not ms-epoch),id,snr,rssi— none can overflow.Changes
src/db/schema/meshcoreNeighbors.ts— PG/MySQLtimestamp+createdAt→bigint('...', { mode: 'number' }). SQLite unchanged (64-bit already).mode: 'number'keeps reads as JS numbers, matchingmeshcore_packet_log, so no read-siteNumber()coercion was needed.src/server/migrations/095_meshcore_neighbor_timestamp_bigint.ts— idempotent migration:ALTER TABLE ... ALTER COLUMN ... TYPE BIGINT, guarded byinformation_schema.columnsdata-type check.ALTER TABLE ... MODIFY COLUMN ... BIGINT NOT NULL, guarded byinformation_schema.COLUMNScheck.src/db/migrations.ts; bumpedsrc/db/migrations.test.tscount to 95 and last-name assertion.Verification
tsc -p tsconfig.server.json --noEmit: no new errors (only the ~5 pre-existingTelemetryChart.tsxfrontend errors remain).🤖 Generated with Claude Code