Skip to content

fix(local): Decode raw envelope attachments only when previewed - #2105

Merged
BYK merged 1 commit into
mainfrom
byk/local-lazy-envelope-attachments
Nov 9, 2026
Merged

BYK merged 1 commit into
mainfrom
byk/local-lazy-envelope-attachments

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

In the Sentry Local viewer, opening a raw envelope's overview decoded every attachment in it right away (base64 → bytes, text decoding) and made a Blob URL for each one. An envelope with several screenshots or videos paid for all of them even if you only wanted one.

This brings over the lazy rendering from getsentry/spotlight#1358:

  • EnvelopeAttachments renders each AttachmentDetail as collapsible. Collapsed rows show the filename, content type and the item header length, without touching the payload.
  • Show preview decodes the attachment, creates the download Blob URL and renders the preview. Hide preview drops the preview and revokes the URL.
  • There's one toggle button that stays mounted in both states and keeps aria-expanded up to date, so keyboard focus isn't lost (this covers the Copilot comment on the spotlight PR).
  • A selected attachment item (Attachments view) doesn't change: it still renders its preview immediately.

Decoding is now memoized on [expanded, item], which also removes the second attachmentBytes call per render that the old effect made.

Screenshots

Raw envelope from the bundled 08-attachments fixture, /envelopes:

Collapsed (nothing decoded) notes.txt and order.json expanded
collapsed expanded

Testing

  • Updated the raw-envelope test in semantic-inspection.test.tsx. It checks that collapsed rows show header metadata and don't call createObjectURL, that expanding decodes and adds the download link, and that collapsing removes the preview while keeping the same button element.
  • apps/local: pnpm run typecheck, pnpm run lint, pnpm run test (322 tests) pass. oxfmt --check is clean.
  • Manual: replayed the bundled fixtures into a local receiver and toggled previews with the mouse and with Enter. Focus stayed on the toggle.

via @BYK.

--

View Session in Sentry

Raw envelope overviews decoded every attachment up front, including
base64 images and video, and created a Blob URL for each one. Attachments
there now start collapsed, show the filename, type and header length, and
decode only when their preview is opened. A single mounted toggle keeps
keyboard focus across expand and collapse. Selected attachment items keep
rendering their preview immediately.

Mirrors the lazy rendering in getsentry/spotlight#1358.

Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
@vercel

vercel Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
sentry-local Ready Ready Preview Nov 9, 2026 1:42pm UTC

Request Review

@BYK
BYK merged commit 7f0be6f into main Nov 9, 2026
30 checks passed
@BYK
BYK deleted the byk/local-lazy-envelope-attachments branch November 9, 2026 14:33
BYK added a commit that referenced this pull request Nov 9, 2026
…2106)

Stacked on #2105.

SDKs send screenshots, view hierarchies and other files along with the
error they belong to, but Sentry Local only listed them in the
Attachments view. You saw the error in one place and had to go find its
screenshot somewhere else. Spotlight shows them under the event (Context
→ Attachments).

Error event details now have an **Attachments** section, placed after
the event fields and before context and breadcrumbs.

- `eventAttachments` in `lib/attachments.ts` matches every `attachment`
item whose envelope header `event_id` equals either the event's own
envelope header `event_id` or its payload `event_id`. That covers
attachments in the same envelope as the event and attachments sent later
in another envelope. It checks both IDs because they don't always match:
in the bundled `08-attachments` fixture the header says `8259…` and the
payload says `9999…`.
- Rows use the collapsed, lazily decoded list from #2105.
`EnvelopeAttachments` is now `AttachmentList` with a `label`, so the
error panel doesn't decode every screenshot just to show a stack trace.
- Errors with no attachments look the same as before. The Attachments
view is unchanged.

## Screenshots

Bundled `08-attachments` fixture, Events → "Captured attachment
examples":

| Collapsed | `order.json` and `page.html` expanded (HTML stays inert
source) |
| --- | --- |
|
![collapsed](https://junior-prod.sentry.dev/public/artifacts/ff92ad1b-2677-4e07-afba-f1021c5944fe.png)
|
![expanded](https://junior-prod.sentry.dev/public/artifacts/f6d171c2-1667-4b60-97e6-f68c3dcbbb8a.png)
|

## Testing

- `event-detail.test.tsx`: an error lists attachments from its own
envelope (header ID different from the payload ID) and from a later
envelope that names the payload ID. It skips another event's attachment,
keeps them collapsed until you click Show preview, and errors with no
attachments render no section.
- `apps/local`: `pnpm run typecheck`, `pnpm run lint` and `pnpm run
test` (324 tests) pass. `oxfmt --check` is clean.
- Manual: replayed the bundled fixtures into a local receiver. The
attachment example event shows its four attachments. The `TypeError`
error shows no section.

<!-- junior-request-attribution:start -->
via @BYK.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:local%3Aweb%3A49f780b5cb01d5ba7e382969 -->

--

[View Session in
Sentry](https://sentry.sentry.io/explore/conversations/local%3Aweb%3A49f780b5cb01d5ba7e382969/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: BYK <126780+BYK@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — bbb3da52 Deployed Nov 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant