From a876f56cc925e1b4b8e6566a235465ceec191b47 Mon Sep 17 00:00:00 2001 From: Rup Sarmah Date: Tue, 21 Jul 2026 14:35:18 +0530 Subject: [PATCH] fix(node): count event bytes correctly so the size limits are enforced --- .changeset/fix-node-event-size-guard.md | 5 ++++ .../segmentio/__tests__/context-batch.test.ts | 29 +++++++++++++++++++ .../src/plugins/segmentio/context-batch.ts | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-node-event-size-guard.md create mode 100644 packages/node/src/plugins/segmentio/__tests__/context-batch.test.ts diff --git a/.changeset/fix-node-event-size-guard.md b/.changeset/fix-node-event-size-guard.md new file mode 100644 index 000000000..b6716ec55 --- /dev/null +++ b/.changeset/fix-node-event-size-guard.md @@ -0,0 +1,5 @@ +--- +'@segment/analytics-node': patch +--- + +Fix the per-event and batch size limits, which were not enforced. `ContextBatch.calculateSize` used a broken byte-count regex (`split(/%..|i/)`) that counted only `%XX` escapes plus the letter "i" instead of UTF-8 bytes, so a ~39 KB event measured as ~21 bytes and passed the 32 KB per-event guard. Restored the correct byte count so oversized events are rejected before they are sent. diff --git a/packages/node/src/plugins/segmentio/__tests__/context-batch.test.ts b/packages/node/src/plugins/segmentio/__tests__/context-batch.test.ts new file mode 100644 index 000000000..c79596b19 --- /dev/null +++ b/packages/node/src/plugins/segmentio/__tests__/context-batch.test.ts @@ -0,0 +1,29 @@ +import { ContextBatch } from '../context-batch' +import { NodeEventFactory } from '../../../app/event-factory' +import { Context } from '../../../app/context' + +const eventFactory = new NodeEventFactory() +const pending = (context: Context) => ({ resolver: () => undefined, context }) + +describe('ContextBatch', () => { + it('rejects an event that exceeds the 32 KB per-event size limit', () => { + // ~40 KB of JSON, well over the 32 KB per-event cap + const event = eventFactory.track( + 'big', + { data: 'a'.repeat(40000) }, + { userId: 'u' } + ) + const batch = new ContextBatch(100) + const result = batch.tryAdd(pending(new Context(event))) + expect(result.success).toBe(false) + if (!result.success) { + expect(result.message).toContain('exceeds maximum event size') + } + }) + + it('accepts a normal small event', () => { + const event = eventFactory.track('small', { ok: true }, { userId: 'u' }) + const batch = new ContextBatch(100) + expect(batch.tryAdd(pending(new Context(event))).success).toBe(true) + }) +}) diff --git a/packages/node/src/plugins/segmentio/context-batch.ts b/packages/node/src/plugins/segmentio/context-batch.ts index 6b1c7b702..10d1faa5b 100644 --- a/packages/node/src/plugins/segmentio/context-batch.ts +++ b/packages/node/src/plugins/segmentio/context-batch.ts @@ -53,7 +53,7 @@ export class ContextBatch { } private calculateSize(ctx: Context): number { - return encodeURI(JSON.stringify(ctx.event)).split(/%..|i/).length + return encodeURI(JSON.stringify(ctx.event)).split(/%..|./).length - 1 } getEvents(): SegmentEvent[] {