Skip to content

Fix ImportError in transformers.exporters on torch < 2.8 - #47711

Merged
IlyasMoutawwakil merged 2 commits into
huggingface:mainfrom
Neal006:fix-exporters-import-on-supported-torch
Aug 3, 2026
Merged

Fix ImportError in transformers.exporters on torch < 2.8#47711
IlyasMoutawwakil merged 2 commits into
huggingface:mainfrom
Neal006:fix-exporters-import-on-supported-torch

Conversation

@Neal006

@Neal006 Neal006 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

CI

What does this PR do?

Fixes #47710.

import transformers.exporters raises ImportError on torch 2.5, 2.6 and 2.7, all inside the
declared torch>=2.5 support range. exporter_executorch.py imports guard_or_true at module
scope, and that symbol was added in torch 2.8 where it replaced definitely_true.
is_torch_available() checks that torch is installed, not which version, so the import runs and
fails. Because exporters/auto.py imports the ExecuTorch exporter eagerly, the ONNX and Dynamo
exporters become unreachable too, on torch versions neither of them needs.

First bad commit is fde2b96b5 (#41992), found with git log -S guard_or_true.

The change

One line moves. That is the whole diff.

guard_or_true moves into _patch_remove_empty_tensors_from_cat, the only function that uses it.
The sibling patch handler in the same file, _patch_dim_order_from_stride, already imports
guard_or_false, guard_or_true function-locally, so this follows existing convention.

No min_versions entry is added. An earlier revision of this PR declared
min_versions = {"torch": "2.8.0"} on ExecutorchExporter; that was wrong and has been dropped.
min_versions is a plain class attribute, so ExecutorchExporter already inherits
{"torch": "2.11.0"} from DynamoExporter, and declaring 2.8.0 here overrode it downward. That
would have let users past validate_environment on torch 2.8 to 2.10 and into a later failure
inside DynamoExporter.export. Thanks to the Copilot review for catching it. The inherited
torch>=2.11.0 floor already covers guard_or_true by a wide margin, so this file needs no gate
of its own.

An earlier revision also added tests/exporters/test_utils.py::ImportSurfaceTest, asserting
guard_or_true is not a module global of exporter_executorch. Removed at @IlyasMoutawwakil's
request.

No new helper, no new dependency, no behavior change on torch >= 2.8.

Verification on torch 2.6.0

before after
import transformers.exporters ImportError OK
from transformers.exporters import AutoHfExporter ImportError OK
AUTO_EXPORTER_MAPPING unreachable ['dynamo', 'executorch', 'onnx']
python utils/checkers.py imports, repo FAILED OK
pytest tests/exporters/test_utils.py collection error, 0 run 13 passed, 2 skipped, 1 failed

The fix was verified against the bug: restoring the module-scope import makes the whole test file
fail collection on torch 2.6.

The one remaining failure, test_from_config_dispatches_dynamo, is
DynamoExporter requires newer versions of: torch>=2.11.0 (found 2.6.0+cu124). That comes from
DynamoExporter.min_versions and my local torch, not from this change. It failed before this PR
too, silently, because nothing in the suite could be collected.

ruff check and ruff format are clean.

Before submitting

I used AI tooling to investigate this, and I have reviewed and verified every changed line and run
the tests and checks above myself.

Who can review?

@IlyasMoutawwakil, since you authored #41992. Review, and merge if it looks right to you. Happy to
switch to raising the declared torch floor instead if you prefer that route.

Copilot AI review requested due to automatic review settings August 2, 2026 13:26

Copilot AI 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.

Pull request overview

This PR fixes an ImportError when importing transformers.exporters on PyTorch versions <2.8 by removing the module-scope import of guard_or_true from the ExecuTorch exporter, ensuring the exporters package remains importable and other exporters (ONNX/Dynamo) remain reachable.

Changes:

  • Removes the module-level guard_or_true import in exporter_executorch.py and defers it to the specific patch factory that needs it.
  • Adds a min_versions gate on ExecutorchExporter to prevent hard crashes and surface a clear requirement message instead.

Comment on lines 103 to 105
required_packages = ["torch", "executorch"]
min_versions = {"torch": "2.8.0"}
tested_versions = {"torch": "2.12.0", "executorch": "1.3.1"}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, fixed. You are right that this relaxed the floor rather than
tightening it: min_versions is a plain class attribute, so ExecutorchExporter
already inherited {"torch": "2.11.0"} from DynamoExporter, and declaring
2.8.0 here overrode it. That would have let users past validate_environment
on torch 2.8 to 2.10 and then failed inside DynamoExporter.export, which is
worse than the clear error they get today.

The line is gone. The inherited torch>=2.11.0 floor stands, and it already
covers guard_or_true (torch 2.8) by a wide margin, so nothing here needs a
gate of its own. The remaining diff is just the import move.

Comment on lines 494 to 500
inputs conservatively (the pass is purely an optimisation).
"""
from executorch.exir.dialects._ops import ops as exir_ops
from torch.fx.experimental.symbolic_shapes import guard_or_true

def patch(self, graph_module, cat_node):
pruned = [arg for arg in cat_node.args[0] if guard_or_true(arg.meta["val"].numel() != 0)]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a test, though not quite the one suggested. Deleting guard_or_true and
reimporting the module means importlib.reload, which re-runs the ~25
register_patch / register_fx_*_fix decorators in this file against the
global registries and leaks that state into every test after it.

tests/exporters/test_utils.py::ImportSurfaceTest asserts instead that
guard_or_true is not in vars(exporter_executorch), which fails on exactly
the regression you describe with no reload and no side effects. Verified by
putting the module-scope import back: the whole test file then fails collection
on torch 2.6.

guard_or_true was added in torch 2.8, but setup.py declares torch>=2.5 and
is_torch_available() does not check the version. Since auto.py imports the
ExecuTorch exporter eagerly, the module-level import took down the ONNX and
Dynamo exporters as well.

Move the import into the only function that uses it, matching
_patch_dim_order_from_stride in the same file. ExecutorchExporter already
inherits min_versions torch>=2.11.0 from DynamoExporter, so no version gate is
added here.

Add a regression test asserting the symbol is not a module global, so the
import cannot drift back to module scope.
@Neal006
Neal006 force-pushed the fix-exporters-import-on-supported-torch branch from b8f3eb1 to 8140ee9 Compare August 2, 2026 13:48
@Neal006
Neal006 requested a review from Copilot August 2, 2026 14:08

Copilot AI 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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

tests/exporters/test_utils.py:139

  • The PR description says it adds min_versions = {"torch": "2.8.0"} on ExecutorchExporter, but the current diff no longer adds/changes min_versions (only the guard_or_true import move + regression test). To avoid confusing reviewers/users, please update the PR description to match the final implementation (or reintroduce the code change if it’s still intended).
class ImportSurfaceTest(unittest.TestCase):
    """`auto.py` imports every exporter module eagerly, so a symbol that only exists on a newer
    torch than `setup.py` declares (`torch>=2.5`) takes the whole `transformers.exporters` package
    down when imported at module scope — ONNX and Dynamo included. Version-gated symbols belong
    inside the function that uses it."""

Comment thread tests/exporters/test_utils.py Outdated
@IlyasMoutawwakil

Copy link
Copy Markdown
Member

thanks, just remove the test please

Requested by @IlyasMoutawwakil in review. The remaining diff is just the
guard_or_true import move.
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

CI recap

Dashboard: View test results in Grafana
Latest run: 30750723670:2
Result: success | Jobs: 16 | Tests: 178,175 | Failures: 0 | Duration: 6h 25m

@IlyasMoutawwakil
IlyasMoutawwakil added this pull request to the merge queue Aug 3, 2026
Merged via the queue into huggingface:main with commit 63a6dc1 Aug 3, 2026
114 checks passed
@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

transformers.exporters raises ImportError on torch < 2.8 while setup.py declares torch>=2.5

4 participants