trtcheck is a static analysis tool for the ONNX → TensorRT conversion step. It reads an ONNX file, runs five independent checkers against a per-version TensorRT operator matrix, and reports whether the model will convert — with a specific remediation for each blocker it finds. Five built-in fixers rewrite the common failure patterns. Analysis runs in seconds and needs no TensorRT install, CUDA, or GPU, so it works on a laptop and in CI.
Install
pip install trtcheck
Or from source for development:
git clone https://github.com/sohams25/trtcheck.git
cd trtcheck
pip install -e ".[dev]"
Python 3.10–3.13, onnx >= 1.15, < 2.0. No platform dependencies beyond
onnx itself — analysis needs no TensorRT, no GPU. Modeled TensorRT
targets: 8.0, 8.6, 10.0, 10.3; each operator entry carries its own
evidence level (official documentation, inferred, or unknown — see
docs/rules.md and the operator pages).
Quick start
$ trtcheck model.onnx
CONVERSION BLOCKED — 1 critical, 0 warning
CRITICAL input Input Input 'input' has dtype UINT8; TensorRT
accepts only FP32, FP16, INT32, or INT8
as graph inputs.
→ Move the UINT8 → FLOAT32 conversion (and
normalization) into your preprocessing
pipeline rather than the model body.
Estimated fix time: 15–30 minutes.
Every report carries one of four verdicts — blocked (a known critical
incompatibility), unverified (no known blocker, but unresolved
conditions: unclassified or custom-domain operators, conditional support
that static analysis cannot settle), likely (all static checks passed
— a prediction, not a guarantee), and verified (an optional real
trtexec build succeeded via --verify-runtime). The exit code is 1
on blocked and 0 otherwise (--fail-on unverified tightens the CI
gate), so the same command works unchanged as a CI gate.
docs/case-studies/uint8-input.md
walks this exact case end to end, including the --fix rewrite that
turns it into a passing graph. Verdict accuracy is measured:
SCORECARD.md publishes precision and recall against
a corpus with known conversion outcomes.
Motivation
trtexec reports conversion problems at engine build time, one at a
time, as C++ log output. Some common failures and what they trace back
to:
trtexec error |
Actually means | Root cause |
|---|---|---|
UNSUPPORTED_NODE: SequenceEmpty |
Your model contains an ONNX sequence op | PyTorch List[Tensor] = [] in forward() |
Assertion failed: convert_dtype: UINT8 |
Graph input dtype is uint8 |
Image preprocessing with np.uint8 |
at least 5 dimensions are required |
MaxPool sees a tensor that lost rank after shape inference |
Dynamic batch combined with reshape |
INT64 weights detected … not natively supported |
A Constant or Initializer is int64 |
torch.LongTensor for argmax / indices |
Network must have at least one output |
Shape inference removed every output | If / Loop with dynamic shape |
trtcheck runs the equivalent compatibility checks statically, so every issue in the model surfaces in one pass, as a named finding with a fix, before an engine build is attempted.
What it checks
| Checker | Catches |
|---|---|
| operator support | Ops missing or partial in the target TRT version (e.g. SequenceEmpty, GroupNormalization on TRT 8.x); documented conditional-support rules (e.g. TopK sorted=0, cubic Resize); honest unverified findings for operators the matrix does not classify and for custom-domain ops that need a TRT plugin |
| precision | UINT8 / INT64 / FLOAT64 / STRING / BFLOAT16 graph inputs, INT64 weights, and FLOAT64 introduced by a Cast or Constant anywhere in the graph |
| dynamic shapes | Two or more symbolic input dims, including dynamic dims encoded as a concrete -1 |
| control flow | Loop with runtime trip count, nested Loop, If, Scan |
| graph structure | Empty outputs, duplicate node names, oversized constants |
Every check descends into If / Loop / Scan subgraph bodies — an
unsupported op buried in a branch is caught, not waved through. Each finding
includes a specific remediation. Not "this is bad" — what to change, where.
What it auto-fixes
--fix runs an audited, transactional pipeline: every fixer works on
an isolated candidate copy, the result must pass full ONNX validation
(strict type/shape inference) before it is kept, and the report shows
which findings were resolved, which remain, and whether any were
introduced. A fixer that crashes — including a third-party plugin — cannot
leave a half-rewritten model. Use --dry-run to preview.
| Fixer | Rewrites |
|---|---|
uint8_input |
Promotes a UINT8 graph input to FLOAT and drops the redundant downstream Cast |
int64_to_int32 |
Casts INT64 initializers to INT32 only when every use is at a schema position that accepts INT32 (e.g. Gather indices) — never Reshape/Slice shape inputs, which require INT64 |
float64_to_float32 |
Casts FLOAT64 initializers to FLOAT32 when no value is NaN, infinite, or out of FP32 range |
drop_dropout |
Removes Dropout nodes that are provably in inference mode (training_mode absent or statically false; mask unused) |
upsample_to_resize |
Rewrites leftover deprecated Upsample nodes as Resize on opset-13+ graphs (nearest / linear) |
trtcheck model.onnx --fix --dry-run # preview
trtcheck model.onnx --fix --output fixed.onnx # apply
Refuses to overwrite the input or an existing output unless you pass
--force.
Measured accuracy
The bench/ harness scores trtcheck's verdicts against a
corpus with known conversion outcomes. Latest run against the TRT 10.3
matrix:
| Corpus | Blocker precision | Blocker recall | Unverified coverage | Total wall time |
|---|---|---|---|---|
| 12 models: 3 from the ONNX Model Zoo, 9 bundled fixtures | 1.000 | 1.000 | 0.250 | 2.3 s |
unverified predictions are never counted as successes — they are
reported separately, split by ground truth. Twelve models is a small
corpus and the failure cases are synthetic, so read this as "the checks
do what they claim on known patterns", not as a field-accuracy estimate.
For the scorecard corpus, ground truth is documented TRT behavior, not a
live trtexec run. Separately, the runtime-verification integration was
smoke-tested against real TensorRT 10.3.0 (official NGC container, 7
representative fixtures: 5 genuine engine builds, 2 genuine parser
failures, full agreement between --verify-runtime and direct trtexec)
— see REAL_TENSORRT_VALIDATION_REPORT.md.
That validates the integration path and those cases, not universal model
compatibility.
SCORECARD.md has the per-model table, the methodology,
and what each run caught (the first run's false negative became the
loop_runtime_trip_count critical check; this run exposed a Clip
coverage gap in the matrix). To grow the corpus, add a model with a
known outcome to bench/manifest.yaml and open a
PR.
How it compares
| trtcheck | Polygraphy | Netron | |
|---|---|---|---|
| Needs TensorRT / GPU | no | yes, for conversion checks | no |
| Time to a verdict | seconds | minutes (builds a real engine) | manual inspection |
| Fix suggestions | per-finding remediation + --fix rewrites |
no | no |
| CI integration | exit code, JSON, GitHub Action | scriptable, needs a GPU runner | no |
| Verdict strength | predicts the build outcome (and says so: four-state verdict with explicit uncertainty; optional --verify-runtime runs trtexec when available) |
proves it | n/a |
Use them together. Polygraphy building an engine is the ground truth; if you have the GPU and the minutes, run it. Netron is for eyeballing a graph once you know which node to look at. trtcheck is the ten-second gate that runs before either: on a laptop, in CI, on every PR.
Usage
# basic check (defaults to TensorRT 10.3)
trtcheck model.onnx
# target a specific TensorRT version
trtcheck model.onnx --target-trt 8.6
# machine-readable output for CI
trtcheck model.onnx --format json --output report.json
# self-contained HTML report
trtcheck model.onnx --format html --output report.html
# filter to blockers only
trtcheck model.onnx --severity critical
# compare two versions of a model (before / after a fix)
trtcheck before.onnx after.onnx --diff
# auto-fix simple issues (transactional; reports resolved/remaining findings)
trtcheck model.onnx --fix --output model_fixed.onnx
# strict CI gate: also fail on unresolved conditions
trtcheck model.onnx --fail-on unverified
# optional: verify with a real TensorRT build (needs trtexec)
trtcheck model.onnx --verify-runtime
Exit code is 1 on a blocked verdict, 0 otherwise; --fail-on unverified also fails on unresolved conditions. Findings carry stable
rule ids (TRT-OP-UNSUPPORTED, TRT-DTYPE-UINT8-INPUT, ...) for CI
filtering — see docs/rules.md and
docs/usage.md.
Full CLI reference: trtcheck --help.
Use it as a GitHub Action
Ships a composite Action that runs on PRs touching *.onnx files and
posts a sticky comment summarizing the report. The dual-workflow
pattern (analyze on PR head with read-only token, comment from base
repo with write token) keeps fork PRs safe.
.github/workflows/trtcheck.yml:
name: trtcheck
on:
pull_request:
paths: ["**/*.onnx"]
permissions:
contents: read
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- id: trtcheck
uses: sohams25/trtcheck@v1
with:
target-trt: "10.3"
fail-on: "critical"
- if: always()
run: |
mkdir -p comment-artifact
cp "${{ steps.trtcheck.outputs.comment-md }}" comment-artifact/body.md
echo "${{ github.event.pull_request.number }}" > comment-artifact/pr-number.txt
- if: always()
uses: actions/upload-artifact@v4
with: { name: trtcheck-comment, path: comment-artifact/ }
Pair with trtcheck-comment.yml to post the comment from the base
repo. Full template at
.github/workflows/example-consumer/trtcheck-comment.yml.
Action inputs
| Input | Default | Purpose |
|---|---|---|
version |
1.1.0 |
trtcheck PyPI version to install |
target-trt |
10.3 |
--target-trt value |
severity |
warning |
--severity filter |
fail-on |
critical |
Exit policy: critical, warning, or never |
paths |
**/*.onnx |
Glob of files to consider |
changed-only |
true |
Only analyze PR-changed files |
base-ref |
(PR base sha) | Base ref to diff against when changed-only is set |
source-path |
(unset) | Install trtcheck from a local path instead of PyPI; used by the selftest workflow |
Action outputs
report-json, comment-md, critical-count, warning-count,
status (pass / fail).
Plugins
Third-party packages can ship checkers, fixers, and reporters via Python entry-points:
[project.entry-points."trtcheck.fixers"]
strip_identity = "your_package.fixers:StripIdentityFixer"
The Protocols live in trtcheck.plugins. Worked example at
examples/trtcheck-extra-fixers/.
Confirm a plugin loaded with trtcheck --list-plugins; filter one out
without uninstalling with trtcheck --disable-plugin NAME.
Full surface at
docs/design/plugin-sdk.md. The public
extension API was frozen at v1.0 and follows semver from here.
The operator matrix
trtcheck/data/operator_matrix.json is a hand-curated mapping from
ONNX operators to their support status across TRT 8.0, 8.6, 10.0, and
10.3. Refresh recipe:
# edit the generator
$EDITOR tools/build_operator_matrix.py
# regenerate the JSON
python tools/build_operator_matrix.py
# validate
pytest tests/test_data_files.py -v
# detect drift against the upstream onnx-tensorrt operators table
python tools/check_matrix_drift.py
Run the drift check before each release to keep the matrix honest.
Contributing
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
./scripts/run-tests.sh # full pytest suite
mypy trtcheck/ # strict type check
black . && isort . # format
TDD is mandatory for new checkers, fixers, and reporters. The full
contribution guide — TDD cycle, operator-matrix refresh recipe, plugin
authoring layout — lives in CONTRIBUTING.md.
Security disclosures: SECURITY.md.
Roadmap
- Grow the bench corpus past nine models with real-world failing
models (detection heads, transformer blocks) and publish a refreshed
SCORECARD.mdper release. - Run the
trtexecleg of the harness on GPU hardware and reconcile the manifest's expected outcomes against live TRT behavior. - Track new TensorRT releases in the operator matrix. The weekly matrix-drift Action already files a tracking issue when the upstream operator table moves.
Shipped: the validation scorecard and the scheduled matrix-drift
Action. See CHANGELOG.md for release notes.
Citation
If trtcheck saves your project some GPU hours, a citation is welcome:
@misc{trtcheck,
title = {trtcheck: a static pre-flight checker for ONNX to TensorRT conversion},
author = {Soham},
year = {2026},
url = {https://github.com/sohams25/trtcheck}
}
Using it in CI? Open a PR adding your project to this section.
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trtcheck-1.1.0.tar.gz.
File metadata
- Download URL: trtcheck-1.1.0.tar.gz
- Upload date:
- Size: 122.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7096de6d9f16652ff495623ca9fbe9019bb663617cac51b5a649c93dc63fccf0
|
|
| MD5 |
a018b5d20ed8120362ec11cd17831545
|
|
| BLAKE2b-256 |
d9c1be93019da940a7f231320dba69a7ce2e45bd8d51bb215f6f3655d94e3647
|
Provenance
The following attestation bundles were made for trtcheck-1.1.0.tar.gz:
Publisher:
release.yml on sohams25/trtcheck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trtcheck-1.1.0.tar.gz -
Subject digest:
7096de6d9f16652ff495623ca9fbe9019bb663617cac51b5a649c93dc63fccf0 - Sigstore transparency entry: 2217925126
- Sigstore integration time:
-
Permalink:
sohams25/trtcheck@de2f27af8c45a39251d5b0534f601d8694a005f7 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/sohams25
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@de2f27af8c45a39251d5b0534f601d8694a005f7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trtcheck-1.1.0-py3-none-any.whl.
File metadata
- Download URL: trtcheck-1.1.0-py3-none-any.whl
- Upload date:
- Size: 70.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1611441fd35d5bd48464ea38a9909b32893b2a452c84b470e9b8ac35a51fe9da
|
|
| MD5 |
889aa70a4d33d8a3e7055fa969fb9b02
|
|
| BLAKE2b-256 |
b487c355c4cc0831a608129d73a596d1a2983e009a34a7d0d3a24a2cfe6914a0
|
Provenance
The following attestation bundles were made for trtcheck-1.1.0-py3-none-any.whl:
Publisher:
release.yml on sohams25/trtcheck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trtcheck-1.1.0-py3-none-any.whl -
Subject digest:
1611441fd35d5bd48464ea38a9909b32893b2a452c84b470e9b8ac35a51fe9da - Sigstore transparency entry: 2217925155
- Sigstore integration time:
-
Permalink:
sohams25/trtcheck@de2f27af8c45a39251d5b0534f601d8694a005f7 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/sohams25
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@de2f27af8c45a39251d5b0534f601d8694a005f7 -
Trigger Event:
push
-
Statement type: