From b91744fa5cd2a0c9471978f8a6db4436c7b1b6f1 Mon Sep 17 00:00:00 2001 From: Sergio Barrio Date: Tue, 22 Sep 2026 14:31:33 +0200 Subject: [PATCH] Fix String(value) throwing when encoding attributes --- .../__tests__/attributesEncoding.test.ts | 25 +++++++++++++++++++ .../sdk/AttributesEncoding/defaultEncoders.ts | 8 ++++-- .../src/sdk/AttributesEncoding/helpers.ts | 12 ++++----- .../core/src/sdk/AttributesEncoding/utils.ts | 8 ++++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts b/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts index 06a292431..87a553d7c 100644 --- a/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts +++ b/packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts @@ -41,6 +41,31 @@ describe('encodeAttributes', () => { expect(warn).toHaveBeenCalled(); }); + it('drops a null-prototype object without throwing', () => { + expect(() => + encodeAttributes({ bad: Object.create(null) }) + ).not.toThrow(); + expect(warn).toHaveBeenCalled(); + }); + + it('drops a value whose toString throws without throwing', () => { + const bad = { + toString() { + throw new Error('boom'); + } + }; + Object.setPrototypeOf(bad, null); + expect(() => encodeAttributes({ bad })).not.toThrow(); + expect(warn).toHaveBeenCalled(); + }); + + it('drops a null-prototype object nested in an array without throwing', () => { + expect(() => + encodeAttributes({ bad: [Object.create(null)] }) + ).not.toThrow(); + expect(warn).toHaveBeenCalled(); + }); + it('drops unsupported root function', () => { const result = encodeAttributes(() => {}); expect(result).toEqual({}); diff --git a/packages/core/src/sdk/AttributesEncoding/defaultEncoders.ts b/packages/core/src/sdk/AttributesEncoding/defaultEncoders.ts index b3634859a..f3dfc240f 100644 --- a/packages/core/src/sdk/AttributesEncoding/defaultEncoders.ts +++ b/packages/core/src/sdk/AttributesEncoding/defaultEncoders.ts @@ -16,7 +16,7 @@ import { } from './errorUtils'; import { encodeAttributesInPlace, sanitizeForJson } from './helpers'; import type { AttributeEncoder, Encodable } from './types'; -import { warn } from './utils'; +import { safeToString, warn } from './utils'; /** Primitives: keep them explicit so the full pipeline is used uniformly. */ export const stringEncoder: AttributeEncoder = { @@ -165,7 +165,11 @@ export const mapEncoder: AttributeEncoder> = { value: sanitizeForJson(v, allEncoders) }); } catch (err) { - warn(`Failed to encode Map key: ${k}. ERROR: ${String(err)}`); + warn( + `Failed to encode Map key: ${safeToString( + k + )}. ERROR: ${safeToString(err)}` + ); } } diff --git a/packages/core/src/sdk/AttributesEncoding/helpers.ts b/packages/core/src/sdk/AttributesEncoding/helpers.ts index c47762312..33c439874 100644 --- a/packages/core/src/sdk/AttributesEncoding/helpers.ts +++ b/packages/core/src/sdk/AttributesEncoding/helpers.ts @@ -5,7 +5,7 @@ */ import type { AttributeEncoder, Encodable } from './types'; -import { formatPathForLog, isPlainObject, warn } from './utils'; +import { formatPathForLog, isPlainObject, safeToString, warn } from './utils'; const MAX_ATTRIBUTES = 256; @@ -69,7 +69,7 @@ export function encodeAttributesInPlace( warn( `Dropped unsupported value in array at '${formatPathForLog( path - )}': ${String(v)}` + )}': ${safeToString(v)}` ); return undefined; }; @@ -94,9 +94,9 @@ export function encodeAttributesInPlace( // Unsupported warn( - `Dropped unsupported value at '${formatPathForLog(path)}': ${String( - value - )}` + `Dropped unsupported value at '${formatPathForLog( + path + )}': ${safeToString(value)}` ); } @@ -138,7 +138,7 @@ export function applyEncoders( return enc.encode(value as never); } } catch (err) { - warn(`Encoder error: ${String(err)}`); + warn(`Encoder error: ${safeToString(err)}`); return undefined; } } diff --git a/packages/core/src/sdk/AttributesEncoding/utils.ts b/packages/core/src/sdk/AttributesEncoding/utils.ts index 1187828d6..a87f73982 100644 --- a/packages/core/src/sdk/AttributesEncoding/utils.ts +++ b/packages/core/src/sdk/AttributesEncoding/utils.ts @@ -11,6 +11,14 @@ export function warn(text: string) { InternalLog.log(`[ATTRIBUTES] ${text}`, SdkVerbosity.WARN); } +export function safeToString(value: unknown): string { + try { + return String(value); + } catch { + return Object.prototype.toString.call(value); + } +} + export function isPlainObject(v: unknown): v is Record { return !!v && typeof v === 'object' && (v as any).constructor === Object; }