Skip to content

Event attachments silently dropped when telemetry processor is enabled (v0.46.0+) #1291

@tphakala

Description

@tphakala

Description

Event attachments added via scope.AddAttachment() are silently dropped when the new telemetry processor is enabled (the default since v0.46.0). The event itself is delivered successfully, but its attachments are missing from the Sentry envelope.

Root Cause

There are two code paths for sending events:

Old path (internalAsyncTransportAdapter.SendEvent in transport.go:935-959) correctly iterates event.Attachments and adds each as a separate envelope item:

for _, attachment := range event.Attachments {
    attachmentItem := protocol.NewAttachmentItem(attachment.Filename, attachment.ContentType, attachment.Payload)
    envelope.AddItem(attachmentItem)
}

New path (Scheduler.sendItem in internal/telemetry/scheduler.go:287-309) only calls item.ToEnvelopeItem() and adds that single item. It never processes event.Attachments:

func (s *Scheduler) sendItem(item protocol.EnvelopeItemConvertible) {
    // ...
    envelope := protocol.NewEnvelope(header)
    envItem, err := item.ToEnvelopeItem()
    // ...
    envelope.AddItem(envItem)
    // No iteration over event.Attachments here
    s.transport.SendEnvelope(envelope)
}

Event.ToEnvelopeItem() (interfaces.go:462-483) serializes the event JSON body into a single envelope item but does not include attachments (attachments must be separate envelope items per the Sentry protocol).

When DisableTelemetryBuffer is false (the default) and no custom Transport is set, setupTelemetryProcessor() runs and all events flow through the new path, dropping attachments.

Reproduction

sentry.Init(sentry.ClientOptions{
    Dsn: "...",
    // DisableTelemetryBuffer defaults to false, enabling the telemetry processor
})

event := sentry.NewEvent()
event.Message = "test with attachment"
event.Level = sentry.LevelInfo

sentry.WithScope(func(scope *sentry.Scope) {
    scope.AddAttachment(&sentry.Attachment{
        Filename:    "test.txt",
        ContentType: "text/plain",
        Payload:     []byte("hello world"),
    })
    sentry.CaptureEvent(event)
})

sentry.Flush(5 * time.Second)
// Event arrives in Sentry, but the attachment is missing

Workaround

Set DisableTelemetryBuffer: true in ClientOptions to force the old transport path:

sentry.Init(sentry.ClientOptions{
    Dsn:                    "...",
    DisableTelemetryBuffer: true,  // forces old path that handles attachments
})

Suggested Fix

In Scheduler.sendItem(), after adding the event envelope item, check if the item has attachments and add them as separate envelope items. Something like:

func (s *Scheduler) sendItem(item protocol.EnvelopeItemConvertible) {
    // ... existing code ...
    envelope.AddItem(envItem)

    // Add attachments if the item supports them
    if attachable, ok := item.(interface{ GetAttachments() []*Attachment }); ok {
        for _, att := range attachable.GetAttachments() {
            envelope.AddItem(protocol.NewAttachmentItem(att.Filename, att.ContentType, att.Payload))
        }
    }

    s.transport.SendEnvelope(envelope)
}

Environment

  • sentry-go v0.46.0 and v0.46.1 (both affected)
  • Go 1.26.2
  • Linux amd64

Metadata

Metadata

Assignees

No one assigned
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions