{"record":{"id":"d236fcacb01c1667","repo":"huggingface/transformers","slug":"0-in-strides-is-not-supported-for-executorch","errorCode":null,"errorMessage":"0 in strides is not supported for ExecuTorch.","messagePattern":"0 in strides is not supported for ExecuTorch\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/exporters/exporter_executorch.py","lineNumber":785,"sourceCode":"    \"executorch.exir.emit._emitter.dim_order_from_stride\",\n    \"executorch.exir.passes.replace_view_copy_with_view_pass.dim_order_from_stride\",\n)\ndef _patch_dim_order_from_stride(_original):\n    \"\"\"Replacement for ``executorch.exir.tensor.dim_order_from_stride``.\n\n    The upstream version compares strides with ``guard_size_oblivious`` to sort\n    them. When the strides are unbacked SymInts (e.g. ``splinter`` slicing on a\n    data-dependent index), the comparison raises ``GuardOnDataDependentSymNode``\n    deep inside ``spec_prop_pass``. Use ``guard_or_true`` / ``guard_or_false``\n    so the sort still produces *a* dim order when the comparison is unbacked —\n    the exact order on unbacked dims doesn't affect correctness, just memory layout.\n    \"\"\"\n    from torch.fx.experimental.symbolic_shapes import guard_or_false, guard_or_true\n\n    def patch(stride):\n        for s in stride:\n            if guard_or_false(s == 0):\n                raise ValueError(\"0 in strides is not supported for ExecuTorch.\")\n\n        class K:\n            __slots__ = (\"stride\",)\n\n            def __init__(self, stride):\n                self.stride = stride\n\n            def __lt__(self, other):\n                return guard_or_true(self.stride < other.stride)\n\n        sorted_dims = [i[0] for i in sorted(enumerate(stride), key=lambda x: K(x[1]), reverse=True)]\n        return tuple(sorted_dims)\n\n    return patch\n\n\n@register_patch(\"executorch\", \"executorch.exir.passes.spec_prop_pass.SpecPropPass.update_placeholder_tensor_specs\")\ndef _patch_update_placeholder_tensor_specs(_original):","sourceCodeStart":767,"sourceCodeEnd":803,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/exporters/exporter_executorch.py#L767-L803","documentation":"A patched version of ExecuTorch's stride-sorting logic (_spec_prop_pass) that checks each stride element with guard_or_false and raises ValueError when a stride contains 0 — ExecuTorch does not support 0-stride (broadcast/expanded) tensors. The patch exists because the upstream comparison throws GuardOnDataDependentSymNode on unbacked SymInts; here a definite 0 stride is instead rejected outright.","triggerScenarios":"Exporting to ExecuTorch with sample inputs or intermediate tensors produced by torch.expand/as_strided with stride 0 (e.g. an expanded bias or mask broadcast along a dimension), so a 0 stride reaches stride propagation.","commonSituations":"Models that call tensor.expand(...) on weights/masks instead of broadcasting; expanded attention masks or position embeddings; inputs passed non-contiguous after a broadcast.","solutions":["Make the offending tensors contiguous: call .contiguous() (or .reshape(...)) on expanded tensors, or use arithmetic broadcasting instead of expand.","Use the exporters' _make_contiguous helper semantics: pass contiguous sample inputs (the shipped prepare hooks already do this for inputs — check model-internal expands).","Find the culprit by scanning the traced graph for expand/as_strided nodes with 0 stride before lowering."],"exampleFix":"# before (model code)\nmask = torch.ones(1, 1, S, S).expand(B, H, S, S)  # stride 0 on B,H\n\n# after (model code)\nmask = torch.ones(1, 1, S, S).expand(B, H, S, S).contiguous()","handlingStrategy":"validation","validationCode":"def inputs_have_zero_stride(inputs) -> list[str]:\n    return [k for k, v in inputs.items() if isinstance(v, torch.Tensor) and 0 in v.stride()]\n\nbad = inputs_have_zero_stride(sample_inputs)\nif bad:\n    sample_inputs.update({k: sample_inputs[k].contiguous() for k in bad})","typeGuard":"def is_executorch_safe(tensor: torch.Tensor) -> bool:\n    return 0 not in tensor.stride()","tryCatchPattern":"try:\n    ExecutorchExporter().export(model, inputs, cfg)\nexcept ValueError as e:\n    if \"0 in strides\" in str(e):\n        # zero-stride tensor is model-internal; locate expand()/as_strided() calls and .contiguous() them\n        raise\n    raise","preventionTips":["Avoid .expand() for stored/broadcast tensors in models destined for ExecuTorch; prefer broadcasting ops or .contiguous()","Run inputs through a make-contiguous pass before export","Scan traced graphs for expand nodes with stride 0 when adding new models to an ExecuTorch matrix"],"tags":["export","executorch","strides","tensor-ops"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}