Skip to content

feat(cli): Upload DXIL shader binaries as debug files - #1943

Merged
BYK merged 3 commits into
getsentry:mainfrom
tustanivsky:feat/shader-difs
Nov 4, 2026
Merged

BYK merged 3 commits into
getsentry:mainfrom
tustanivsky:feat/shader-difs

Conversation

@tustanivsky

@tustanivsky tustanivsky commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Sentry can now name the shader that caused a GPU crash, but only if it has the game's compiled shaders. Unreal Engine builds export them as .dxil files (one per shader, over ten thousand per game). This PR lets sentry debug-files upload upload them as dxil debug files and makes the upload path fast enough for sets of that size.

This is the toolkit version of getsentry/sentry-cli#3489, which was implemented earlier to test with the Unreal SDK which has not migrated to the Sentry toolkit yet (getsentry/sentry-unreal#1680).

Changes

  • The scanner recognises a DXIL container by its header, before the files reach the object parser, which does not know shaders. The debug id is the 32-hex compiler hash the engine uses as the file name. dxil joins the --type list; --id accepts the bare file name or the hyphenated id. Shaders have none of the symbol/unwind/source features the other formats are filtered on, so those filters do not apply to them.
  • The GPU crash decoder identifies a shader by NVIDIA's own hash of it, which only NVIDIA's Windows library can compute. The Sentry Unreal plugin computes it at build time and writes sentry-shader-manifest.tsv next to the shaders. The CLI reads that manifest once per directory and sends the hash and the shader group as the new code_id and shader_group assemble fields. Without a manifest the shader is uploaded without them.
  • Assemble requests are sent in batches of a thousand files.
  • Missing chunks are uploaded in batched requests, packed up to the server's chunksPerRequest and maxRequestSize limits, with a chunk shared by several files sent once. They were sent one request per chunk, so ten thousand small files took a lot of time.
  • The assemble request is repeated right after the chunks are delivered, and the processing wait starts from that point. Before, the wait started before the upload; when the upload alone outlasted it, the command exited without the request that starts processing, and reported the files as not found or timed out although every chunk was on the server.

The last three points apply to every debug file type. Files that are not shaders otherwise take exactly the old path. debug-files find and check do not learn about shaders here.

Possible Follow-ups

Shader PDBs would add source file and line context to GPU crashes. They are left out for now because the server cannot use them yet, but the manifest already lists the PDB that belongs to each binary.

Related

`debug-files upload` recognises DXIL containers (the compiled shaders an
Unreal Engine cook exports) and uploads them as `dxil` debug files, which
Sentry uses to name the faulting shader of a GPU crash. The debug id is the
compiler hash in the file name. When the Sentry Unreal plugin's
`sentry-shader-manifest.tsv` sits next to the files, each shader's Aftermath
hash and shader group are sent as the new `code_id` and `shader_group`
assemble fields.

Assemble requests are sent in batches of a thousand files for every debug
file type: a shader set is around ten thousand files per build, and a single
assemble request for all of them ran for minutes on the server.
Missing chunks were uploaded one request per chunk, so a debug file set of
ten thousand small files took twenty minutes, and the processing deadline
started before that upload. When the upload outlasted the deadline the
command gave up without sending the assemble request that starts
processing, reporting the files as not found or timed out although every
chunk was on the server.

Chunks are now packed into requests up to the server's chunksPerRequest and
maxRequestSize limits, a chunk shared by several files is sent once, the
assemble request is repeated right after the chunks are delivered, and the
wait budget starts from that point.
@vercel

vercel Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated
sentry-local Skipped Skipped Nov 4, 2026 3:07pm UTC

Request Review

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

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.

Reviewed by Cursor Bugbot for commit 8e6a441. Configure here.

Comment thread packages/cli/src/lib/dif/scan.ts Resolved
`--id` could select a DXIL shader by its 32-hex file stem, but `--require-all`
compared the same value against the hyphenated id and reported it missing.
normalizeDebugId now hyphenates a bare 32-hex id, so filtering, --require-all
and find agree, and the shader-specific stem match is gone.
@BYK
BYK enabled auto-merge (squash) November 4, 2026 15:24
@BYK

BYK commented Nov 4, 2026

Copy link
Copy Markdown
Member

Thanks a lot!

@BYK
BYK merged commit 27960b7 into getsentry:main Nov 4, 2026
18 checks passed

This branch was previously deployed

1 inactive deployment
Preview — 39e37f90 Deployed Nov 4, 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.

2 participants