Environment
-
TVM version: main @ 48242ec33403f2b6e4fac6e763ca7a683fb9d5df (2026-09-03, reports 0.26.dev0) and release 0.26.0.
-
Build / install: source build for main; venv wheel for 0.26.0
-
OS / Python: Ubuntu 24.04.3 LTS, x86_64, Python 3.10
-
Reference implementation: onnxruntime 1.23.2
-
Target: target-independent — the failure is at import, before any build. Both llvm and cuda unreachable.
-
Pipeline coverage: the failure is at import, before any pipeline runs, so fusion is irrelevant — but reported explicitly anyway. Verified 2026-09-06 on 0.26.0, llvm:
get_pipeline("default_build") (no FuseOps/FuseTIR) — fails (TypeError in from_onnx)
get_pipeline("zero") (fuses) — fails, identical message
- forced
FuseOps + FuseTIR — fails, identical message
Minimal reproducer
Two-node ONNX graph: a Slice with runtime starts/ends, feeding a Max. model.onnx + feed.npz + run.py attached.
import numpy as np, onnx, onnxruntime as ort
from tvm.relax.frontend.onnx import from_onnx
model = onnx.load("model.onnx"); feed = dict(np.load("feed.npz"))
onnx.checker.check_model(model, full_check=True) # the model is valid ONNX
print("onnxruntime says:", ort.InferenceSession(model.SerializeToString(),
providers=["CPUExecutionProvider"]).run(None, feed))
from_onnx(model, shape_dict={k: list(v.shape) for k, v in feed.items()},
keep_params_in_input=False) # <-- TypeError here
Expected vs actual
- Expected: the model imports. It passes
onnx.checker.check_model(..., full_check=True) and onnxruntime executes it and returns the correct tensor.
- Actual:
TypeError: object of type 'NoneType' has no len()
raised inside the importer, with no indication of which node or which input is at fault.
Root cause (if known)
MultiInputBase._impl_v1 reads inp.ty.shape for every input and passes it to compute_broadcast_shape, which does len(shape_a). An input whose struct-info shape is unknown — R.Tensor(dtype=..., ndim=2), which is what R.dynamic_strided_slice produces — has shape is None, so len(None) raises.
Corroborating observations on the same graph and the same build:
Add on the same tensor imports fine — the elementwise binary path does not go through this helper.
- A single-input
Max on the same tensor fails differently (Found null pointer node), i.e. the unknown-shape case is unhandled on more than one branch.
Max, Min, Sum and Mean all fail identically, which is exactly the set that routes through MultiInputBase.
Never fixed; present on 0.26.0 and main @ 48242ec alike.
Why this is a bug (not tolerance / not undefined behaviour)
The model is valid ONNX, the checker accepts it, and onnxruntime runs it. An importer must either support an input with unknown static shape or reject it with a diagnostic that names the node; len(None) is neither. Unknown-shape struct info is a first-class state in Relax (R.Tensor(dtype=..., ndim=k)), produced by TVM's own R.dynamic_strided_slice, so this is not an exotic input.
Related, not duplicate. Open issue #20175 is the symbolic-dimension failure of the same helper (ValueError: Cannot use and / or / not operator to Expr). Merged PR #20218 (2026-08-30, i.e. before 48242ec) fixed that path — verified: #20175's own reproducer imports successfully on main — but left compute_broadcast_shape's len(shape_a) unguarded against None. Our reproducer still fails on that same commit.
How found
Found by EquiAutomaton (equivalence-graph differential testing against onnxruntime). Depth-0 — two nodes.
Reproducer archive
TVM-C4-reproducer.zip
Triage
Environment
TVM version:
main @ 48242ec33403f2b6e4fac6e763ca7a683fb9d5df(2026-09-03, reports0.26.dev0) and release0.26.0.Build / install: source build for main; venv wheel for 0.26.0
OS / Python: Ubuntu 24.04.3 LTS, x86_64, Python 3.10
Reference implementation: onnxruntime 1.23.2
Target: target-independent — the failure is at import, before any build. Both
llvmandcudaunreachable.Pipeline coverage: the failure is at import, before any pipeline runs, so fusion is irrelevant — but reported explicitly anyway. Verified 2026-09-06 on
0.26.0,llvm:get_pipeline("default_build")(no FuseOps/FuseTIR) — fails (TypeErrorinfrom_onnx)get_pipeline("zero")(fuses) — fails, identical messageFuseOps+FuseTIR— fails, identical messageMinimal reproducer
Two-node ONNX graph: a
Slicewith runtimestarts/ends, feeding aMax.model.onnx+feed.npz+run.pyattached.Expected vs actual
onnx.checker.check_model(..., full_check=True)and onnxruntime executes it and returns the correct tensor.raised inside the importer, with no indication of which node or which input is at fault.
Root cause (if known)
MultiInputBase._impl_v1readsinp.ty.shapefor every input and passes it tocompute_broadcast_shape, which doeslen(shape_a). An input whose struct-info shape is unknown —R.Tensor(dtype=..., ndim=2), which is whatR.dynamic_strided_sliceproduces — hasshape is None, solen(None)raises.Corroborating observations on the same graph and the same build:
Addon the same tensor imports fine — the elementwise binary path does not go through this helper.Maxon the same tensor fails differently (Found null pointer node), i.e. the unknown-shape case is unhandled on more than one branch.Max,Min,SumandMeanall fail identically, which is exactly the set that routes throughMultiInputBase.Never fixed; present on
0.26.0andmain @ 48242ecalike.Why this is a bug (not tolerance / not undefined behaviour)
The model is valid ONNX, the checker accepts it, and onnxruntime runs it. An importer must either support an input with unknown static shape or reject it with a diagnostic that names the node;
len(None)is neither. Unknown-shape struct info is a first-class state in Relax (R.Tensor(dtype=..., ndim=k)), produced by TVM's ownR.dynamic_strided_slice, so this is not an exotic input.Related, not duplicate. Open issue #20175 is the symbolic-dimension failure of the same helper (
ValueError: Cannot use and / or / not operator to Expr). Merged PR #20218 (2026-08-30, i.e. before48242ec) fixed that path — verified: #20175's own reproducer imports successfully on main — but leftcompute_broadcast_shape'slen(shape_a)unguarded againstNone. Our reproducer still fails on that same commit.How found
Found by EquiAutomaton (equivalence-graph differential testing against onnxruntime). Depth-0 — two nodes.
Reproducer archive
TVM-C4-reproducer.zip
Triage