Skip to content

fix: Heap dump files are now deleted from disk once they have been sent to Sentry - #5481

Merged
jamescrosswell merged 5 commits into
getsentry:mainfrom
XAN9xXx:fix/heapdump-cleanup-on-oversized-attachment
Aug 19, 2026
Merged

fix: Heap dump files are now deleted from disk once they have been sent to Sentry#5481
jamescrosswell merged 5 commits into
getsentry:mainfrom
XAN9xXx:fix/heapdump-cleanup-on-oversized-attachment

Conversation

@XAN9xXx

@XAN9xXx XAN9xXx commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Description

Heap dump (.gcdump) files created by the SDK were left on disk after being processed. This affected both successfully sent heap dumps and oversized heap dumps that were dropped before sending, potentially causing these files to accumulate over time.
This PR introduces a dedicated AttachmentType.HeapDump and opens the corresponding file streams with FileOptions.DeleteOnClose. Cleanup is therefore tied to the attachment stream and envelope lifecycle:

  • A successfully processed heap dump is deleted when its stream is closed.
  • An oversized heap dump remains owned by the original envelope and is deleted when that envelope is disposed.
  • When caching is enabled, the heap dump is first serialized into the cache. The source file can then be deleted while the cached copy remains available for sending.
  • Non-heap-dump file attachments retain their existing behavior and are not deleted.

Changes

  • Added AttachmentType.HeapDump.
  • Marked heap dumps created by CaptureHeapDump with the new attachment type.
  • Added deleteOnClose support to FileAttachmentContent.
  • Configured SentryHint to enable FileOptions.DeleteOnClose only for heap dump attachments.
  • Added the event.heapdump envelope attachment-type mapping.
  • Updated the public API approval snapshots for the new enum value and constructor overload.
  • Added tests covering heap dump cleanup, regular file attachments, oversized attachments, successful sends, and cached sends.

Testing

Added tests verifying that:

  • A heap dump file exists while its attachment stream is open and is deleted when the stream is closed.
  • A regular file attachment is not deleted when its stream is closed.
  • An oversized heap dump remains on disk until the original envelope is disposed.
  • A successfully sent heap dump is deleted.
  • With caching enabled, the heap dump is copied into the cache before the source file is deleted, and the cached content is still sent successfully.

The separate Spotlight envelope-item stream-sharing issue discovered during this work is tracked in #5499 .
Fixes #4009

@github-actions github-actions Bot added the risk: high PR risk score: high label Aug 12, 2026
Comment thread src/Sentry/Http/HttpTransportBase.cs Outdated

@jamescrosswell jamescrosswell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @XAN9xXx . I think it might not have been clear from the issue what we were trying to achieve though.

Your current PR would only delete heap dumps if they exceeded the maximum size and we were unable to send these to Sentry. Other heap dumps that are successfully sent to Sentry would stay on disk forever.

We originally wanted to remove any heap dumps that had been successfully sent to Sentry - these are no longer required as they're now available in the Sentry dashboard.

Bruno's comment was that we should also remove heap dumps that we failed to send, since (and especially since these are large) these could easily exhaust available disk space on some servers.

BackgroundWorker.DoWorkAsync does using var _ = envelope around the send, so the envelope — and the FileStream — is disposed once the background worker has finished with it... using FileOptions.DeleteOnClose (only for heap dumps) might be a good way to deal with this.

Using FileOptions.DeleteOnClose also has the advantage that it would allow cleaning up gcdump files even when CacheDirectoryPath is set:

  1. Worker awaits _transport.SendEnvelopeAsync(envelope) → CachingTransport.StoreToCacheAsync
  2. That awaits envelope.SerializeAsync(stream, …) (CachingTransport.cs:486), which copies the .gcdump bytes into the cache file
  3. Returns → worker's using disposes the envelope → FileStream closes → dump deleted

So the original is only removed once a copy exists in the cache directory. The CachingTransport send reads from that copy, and InnerProcessCacheAsync deletes the cache file afterwards.

@XAN9xXx

XAN9xXx commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the explanation @jamescrosswell , that clarifies things a lot — makes sense to use FileOptions.DeleteOnClose instead of what I had.

My laptop is currently being repaired, so I likely won't get back to this for a few days. Will follow up once I'm back!

@XAN9xXx

XAN9xXx commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@jamescrosswell Reworked this using FileOptions.DeleteOnClose as suggested

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5d51697. Configure here.

Comment thread src/Sentry/FileAttachmentContent.cs
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.23810% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 74.76%. Comparing base (3fe027d) to head (48eed54).
⚠️ Report is 17 commits behind head on main.

Files with missing lines Patch % Lines
src/Sentry/Internal/Hub.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5481      +/-   ##
==========================================
+ Coverage   74.73%   74.76%   +0.02%     
==========================================
  Files         513      513              
  Lines       18744    18759      +15     
  Branches     3666     3669       +3     
==========================================
+ Hits        14009    14025      +16     
  Misses       3863     3863              
+ Partials      872      871       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jamescrosswell jamescrosswell changed the title fix: delete heap dump file when attachment exceeds size limit fix: Heap dump files are now deleted from disk once they have been sent to Sentry Aug 19, 2026

@jamescrosswell jamescrosswell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a few tests and made a couple of tweaks to align with the coding styles in the repo (hope you don't mind).

Thank you very much for the contribution and integrating all the feedback @XAN9xXx !

@jamescrosswell
jamescrosswell merged commit 2be688c into getsentry:main Aug 19, 2026
47 checks passed
@XAN9xXx

XAN9xXx commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review and for helping improve the PR! Glad to contribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Heap dumps should be deleted once they've been captured

2 participants