Repository navigation
fix: drop attachments whose stream turns out empty when the envelope is sent - #5787
Merged
Merged
Conversation
Non-seekable attachment streams have no known length when the envelope is created, so the existing zero-length check can't catch them. Skip the item at serialization time, once its payload is buffered and before its header is written. Co-Authored-By: Claude <noreply@anthropic.com>
Keeps explicit length-0 items, as in the envelope spec's framing examples, serializing as before. Co-Authored-By: Claude <noreply@anthropic.com>
Deserialization strips the length header, so keying the drop on an unknown length also dropped deliberately empty attachments after a cache round trip. Key it on the payload built from a stream of unknown length instead. Co-Authored-By: Claude <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5787 +/- ##
==========================================
+ Coverage 76.13% 76.15% +0.02%
==========================================
Files 528 528
Lines 19579 19590 +11
Branches 3829 3835 +6
==========================================
+ Hits 14906 14919 +13
+ Misses 3791 3790 -1
+ Partials 882 881 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
bitsandfoxes
marked this pull request as ready for review
October 27, 2026 14:12
bitsandfoxes
requested review from
jamescrosswell and
ric-oliv
as code owners
October 27, 2026 14:12
ric-oliv
approved these changes
Oct 27, 2026
ric-oliv
left a comment
Member
There was a problem hiding this comment.
One comment, but it looks good to me!
Relay's item parser rejects a trailing lone newline with UnexpectedEof, dropping the whole envelope, but Envelope.DeserializeAsync skips it, so no test caught Envelope writing the newline for a dropped item. Co-Authored-By: Claude <noreply@anthropic.com>
27 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Empty attachments are supposed to be skipped, but an attachment backed by a non-seekable stream that turns out empty gets sent with
length: 0, and Relay stores an empty file on the event.Envelope.AddEnvelopeItemFromAttachmentonly skips an attachment whenstream.TryGetLength()returns0.null(unknown length), so the item is kept.length: 0.sentry-unityhits this regularly: its screenshot attachment returns a non-seekable stream so thatEnvelope.FromEventdoesn't block waiting for the end-of-frame capture. When the screenshot is discarded (SetBeforeSendScreenshotreturnsnull), times out or fails, the event shows an emptyscreenshot.jpg. See getsentry/sentry-unity#2835.Fix
Serialization is the first point where the payload size is known, so the check happens there:
Envelope.Serialize/SerializeAsyncskip an attachment item when it came from an attachment stream of unknown length and its buffered payload is empty. The item header and its trailing newline are both left out.Did not add '<file>' to envelope because the attachment was empty.What stays the same
length: 0are kept. The envelope spec's "Envelope with 2 empty attachments" example, whichEnvelopeTestsmirrors, serializes as before.EnvelopeItem.Serialize/SerializeAsynckeep their signatures and always write. They delegate to newinternaloverloads that return whether the item was written, soEnvelopecan skip the trailing newline as well.length, so the check keys on the payload type (BufferedStreamSerializable) rather than the header, and a deliberately empty attachment survives the round trip, as it does onmain.Edge case
An envelope whose only item gets dropped, e.g. an empty non-seekable attachment sent via
Hub.CaptureAttachment, goes out as a header-only envelope. Relay accepts it and stores nothing:handle_managed_envelopereturns early whenenvelope.is_empty(). The only cost is the request.Tests
AttachmentSerializationTests:Serialization_EmptyNonSeekableStreamAttachment_DropsAttachmentandSerialization_EmptyNonSeekableStreamAttachmentSynchronously_DropsAttachment: attach an empty non-seekable stream throughEnvelope.FromEvent, serialize async and sync, then deserialize again. Both failed before this change.Serialization_EmptyAttachmentOfKnownLengthAfterRoundTrip_KeepsAttachment: round-trips a known-length empty attachment through serialize → deserialize → serialize and checks it's kept.🤖 Generated with Claude Code