Uh oh!
There was an error while loading. Please reload this page.
feat(core): Support array attributes for spans, logs and metrics - #20427
Conversation
Relay's wire contract (AttributeType enum in relay-event-schema) defines
exactly five `type:` tags: boolean, integer, double, string, array.
The SDK's AttributeTypeMap previously declared typed array variants
(`string[]`, `integer[]`, etc.) that Relay does not recognize - these
were never actually emitted because the runtime serializer only handled
primitives, so array-valued attributes silently dropped.
This change:
- Collapses the four `x[]` variants in AttributeTypeMap into a single
`array` variant whose value is `Array<string> | Array<number> | Array<boolean>`.
- Extends getTypedAttributeValue to auto-detect homogeneous primitive
arrays and emit `{type: 'array', value: [...]}`.
- Adds an isHomogeneousPrimitiveArray guard so mixed-type and nested
arrays remain unsupported (dropped by default, stringified under
the fallback path).
- Updates tests to cover the new typed-array path (including empty
arrays, unit preservation, and mixed-type drop/stringify).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>size-limit report 📦
|
Arrays that were previously dropped by the serializer now ship as native array attributes (`type: 'array'`). Update the affected integration test expectations and bump size-limit thresholds for the five bundle scenarios whose gzipped/uncompressed sizes grew from the new serializer logic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the size-limit increases for the five bundle scenarios that grew from adding homogeneous primitive array support. Test expectation updates from the previous commit stay. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-apply the size-limit bumps needed to account for the new homogeneous-primitive-array detection logic. Five scenarios grew past their thresholds: - @sentry/browser (incl. Metrics & Logs): 28 → 29 KB - CDN Bundle (incl. Logs, Metrics): 30 → 31 KB - CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed: 258.5 → 259 KB - CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed: 268 → 269 KB - CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed: 271.5 → 272 KB Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
…72 KB Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| } | ||
| } | ||
| function isHomogeneousPrimitiveArray(arr: unknown): arr is Array<string> | Array<number> | Array<boolean> { |
There was a problem hiding this comment.
q: Was it previously decided that SDKs have to guarantee homogeneity? Just wondering if we really have to iterate over the entire array for every array.
There was a problem hiding this comment.
Jap fair question, we are still discussing that one 😅
There was a problem hiding this comment.
Talked to ingest: We don't need any SDK-side runtime validation.
nicohrubec
commented
Apr 29, 2026
Converting back to draft until we have a definitive answer for SDK validation. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f896f3a. Configure here.
| */ | ||
| function getTypedAttributeValue(value: unknown): TypedAttributeValue | void { | ||
| if (Array.isArray(value) && value.length !== 0) { | ||
| return { value, type: 'array' }; |
There was a problem hiding this comment.
Mixed-type array console parameters silently dropped by Relay
Medium Severity
The getTypedAttributeValue function now converts all non-empty arrays to { type: 'array' } before the stringify fallback path is reached. This means SDK-internal sentry.message.parameter.X attributes created by createConsoleTemplateAttributes from mixed-type console args (e.g. console.log('Array:', [1, 2, 3, 'string'])) are now sent as array attributes instead of being stringified. Since Relay drops non-homogeneous arrays, these template parameters will be silently lost — a regression from the previous behavior where they were preserved as stringified values. The body text is unaffected, but structured template parameter data is lost for mixed-type arrays.
Reviewed by Cursor Bugbot for commit f896f3a. Configure here.
There was a problem hiding this comment.
this is basically what I described in the PR description, we can discuss it but I think this is a tradeoff we have to make. don't think we can really solve this unless we do runtime inspection of the types of elements in arrays
| export type Attributes = Record<string, TypedAttributeValue>; | ||
| export type AttributeValueType = string | number | boolean | Array<string> | Array<number> | Array<boolean>; | ||
| export type AttributeValueType = string | number | boolean | Array<unknown>; |
There was a problem hiding this comment.
h: Do we really want Array<unknown>? Every change that follows would be breaking from here on.
| value: expect.any(Number), | ||
| }, | ||
| // TODO: 'device.archs' is set but arrays are not yet serialized in span attributes | ||
| 'device.archs': { |
| 'integer[]': Array<number>; | ||
| 'double[]': Array<number>; | ||
| 'boolean[]': Array<boolean>; | ||
| array: Array<string> | Array<number> | Array<boolean>; |
There was a problem hiding this comment.
q: Would be BigInt supported as well? I think this is a broader question actually
There was a problem hiding this comment.
Mhm not sure. I assume relay enforces some number maximum but no idea what that is.
logaretm
left a comment
There was a problem hiding this comment.
@nicohrubec Do u think it is worth warning in debug if we detect non-homogenous attributes in the array?
Just to ease detecting this for the end user.
| * https://github.com/getsentry/sentry-javascript/pull/18165 | ||
| */ | ||
| function getTypedAttributeValue(value: unknown): TypedAttributeValue | void { | ||
| if (Array.isArray(value) && value.length !== 0) { |
There was a problem hiding this comment.
@nicohrubec q: what happens in empty arrays? are they still stringified?
There was a problem hiding this comment.
as discussed I'll switch that logic to early return for empty arrays so they get dropped for both fallback/non-fallback paths. the way it is right now if fallback is enabled we send a stringified empty array if the fallback is on
There was a problem hiding this comment.
actually after further discussion we won't be dropping empty arrays (independent of fallback on/off)
Now that array attributes are serialized, `device.archs` is no longer dropped — uncomment and enable the assertions in integration tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.



Adds array attribute support for spans, logs, and metrics. Relay only supports primitive homogeneous arrays (all elements have the same primitive type). However, any attributes with non-conforming arrays will be dropped by Relay, so there is no need for runtime validation on the SDK end.
This change as is comes with a behavioral change for user-defined logs and metrics. If users previously set array attributes for logs/metrics then these were previously sent to Sentry stringified, now these will be sent as arrays. After discussion with product teams we also decided not to drop empty arrays.
Closes#20651
Closes#20438