Skip to content

fix: don't attach empty heap profiles to Sentry memory alerts (APP-5199) - #14754

Draft
warp-agent-staging[bot] wants to merge 1 commit into
masterfrom
fix/empty-heap-profile-sentry-attachment
Draft

fix: don't attach empty heap profiles to Sentry memory alerts (APP-5199)#14754
warp-agent-staging[bot] wants to merge 1 commit into
masterfrom
fix/empty-heap-profile-sentry-attachment

Conversation

@warp-agent-staging

Copy link
Copy Markdown
Contributor

Description

Sentry memory alerts from macOS have been arriving with a heap-profile.pb attachment that has no content, which makes them impossible to triage — there are no allocation call stacks to analyze. The client has a silent-failure path that produces exactly that outcome.

In app/src/profiling.rs:

  1. dump_jemalloc_heap_profile_inner (non-Linux branch) shells out to the bundled pprof helper (Contents/Helpers/pprof) against http://127.0.0.1:9277/debug/pprof/heap. It checks only output.status.success() and then std::fs::reads the output path. If pprof exits 0 without writing anything usable — local profiling HTTP server unreachable, error body returned, helper missing or quarantined — the read yields an empty Vec<u8> that propagates as Ok(vec![]).
  2. dump_jemalloc_heap_profile attaches that buffer unconditionally, captures the "Excessive memory usage detected" message, and logs "Sent heap profile to Sentry". The alert fires with a useless attachment and nothing indicates the capture failed.

Linux is unaffected: it dumps in-process via dump_jemalloc_pprof_bytes (jemalloc_pprof), with no helper binary, HTTP round-trip, or output file involved.

This change:

  • treats an empty dump as an error in dump_jemalloc_heap_profile_inner, including pprof's own stderr in the error so the cause is diagnosable (and applies the same guard to the Linux in-process dump);
  • skips the Sentry report entirely when there is no usable profile, instead of claiming success. This matches how every other dump failure is already handled (log, no capture);
  • also stops dump_heap_profile_to_disk from writing a zero-byte profile file.

Evidence

Sentry issue 7259255054 ("Excessive memory usage detected", 3,471 events / 2,467 users). Two consecutive events each carry exactly one heap-profile.pb:

  • event 815020b5f71a461387bf9d42a663185b → attachment 23766597477, reported size 11,590 B
  • event c36ffdaf68ac4bc7b0526ccdb862e5bf → attachment 23766706070, reported size 8,576 B

Both hash to SHA1 da39a3ee5e6b4b0d3255bfef95601890afd80709 — the SHA1 of empty content — and neither yields a usable payload. Affected build: mac_stable_release, release v0.2026.07.29.09.05.stable_02. The spikes themselves are real (memory_breakdown: ~10.28 GB resident, ~10.04 GB footprint, ~17 MB GPU).

One caveat, stated plainly: Sentry reports non-zero sizes for attachments whose content hashes as empty. Had the client uploaded zero bytes, the reported size would be 0. So a Sentry-side ingestion/storage problem may also be in play, and this client path may not be the sole mechanism behind those two specific attachments. The silent-failure path fixed here is a genuine defect either way — it can emit an empty profile and label it a success — but it should not be assumed to fully explain the observed empty attachments until the ingestion side is checked.

Linked Issue

APP-5199. Unblocks APP-4849, which tracks the repeated triage runs on Sentry 7259255054 that dead-end because the profile is unusable.

Testing

Validated in a Linux cloud environment, which constrains what could be exercised — stated explicitly rather than implied:

  • cargo check -p warp --features heap_usage_tracking — passes (app crate type-checked).

  • cargo clippy -p warp --features heap_usage_tracking -- -D warnings — passes with no lints.

  • rustfmt --check with the repo's config (.rustfmt.toml, imports_granularity=Module, group_imports=StdExternalCrate) — clean.

  • Not run: the macOS branch of dump_jemalloc_heap_profile_inner is cfg-gated out on Linux, so it was not compiled here (no macOS toolchain/SDK available). It was reviewed by inspection; output remains in scope at the new bail and the error uses an inlined format arg. A macOS build is needed to confirm.

  • Not added: no unit test. The failing path is a subprocess invocation of a bundled helper inside a cfg-gated async function; testing it meaningfully would require injecting the pprof invocation behind a seam, which is a larger refactor than this fix warrants. Happy to add it if reviewers prefer.

  • I have manually tested my changes locally with ./script/run

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-NONE

Conversation: https://staging.warp.dev/conversation/8b0bcf02-f31f-4d8c-836f-ff051ff0e906
Run: https://oz.staging.warp.dev/runs/019fd445-8892-779e-93d2-f4f49c912df2

This PR was generated with Oz.

The macOS heap profile path shells out to the bundled `pprof` helper and
only checks its exit status before reading the output file. When `pprof`
exits 0 without writing anything usable, the read yields zero bytes that
propagate as `Ok(vec![])`, get attached to the Sentry event as
`heap-profile.pb`, and are reported as a success. The resulting alert
fires with an attachment that has no allocation samples, so it cannot be
triaged, and nothing in the logs signals that the capture failed.

Treat an empty dump as an error, surfacing pprof's own stderr so the
cause is diagnosable, and skip the Sentry report entirely when no usable
profile exists rather than claiming one was sent.

Co-Authored-By: Oz <oz-agent@warp.dev>
@cla-bot cla-bot Bot added the cla-signed label Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant