jax-ml/jax · error · ValueError
end must be greater than start, but got: {end} <= {start}
Error message
end must be greater than start, but got: {end} <= {start} What it means
_make_range builds a Triton make_range op, which requires a strictly increasing (start, end) pair; end <= start is rejected because Triton ranges must be non-empty and ascending. It is hit from iota lowering, offset computation from BlockIdMapping/indices, and argreduce, all of which derive (start, end) from block sizes or index ranges.
Source
Thrown at jax/_src/pallas/triton/lowering.py:1498
sharding):
iota = _make_range(0, shape[dimension])
iota = _cast(iota, jnp.int32, dtype)
for i in range(len(shape)):
if i != dimension:
iota = _expand_dims(iota, i)
return _bcast_to(iota, shape)
def _element_type(t: ir.Type) -> ir.Type:
if isinstance(t, ir.RankedTensorType):
return ir.RankedTensorType(t).element_type
else:
return t
def _make_range(start: int, end: int) -> ir.Value:
if end <= start:
raise ValueError(
f"end must be greater than start, but got: {end} <= {start}"
)
if max(start, end) >= 2**32:
raise ValueError("start and end must fit in int32")
return tt_dialect.make_range(
ir.RankedTensorType.get([end - start], ir.IntegerType.get_signless(32)),
start,
end,
)
def _full(t: ir.Type, v: Any) -> ir.Value:
element_type = _element_type(t)
if isinstance(element_type, ir.IntegerType):
result = arith_dialect.constant(element_type, int(v))
elif isinstance(element_type, ir.FloatType):
result = arith_dialect.constant(element_type, float(v))
else:View on GitHub (pinned to 1e1c6a8fc0)
Solutions
- Validate that every dimension used for iota/arange/indices is >= 1 and clamp or skip execution for size-0 inputs
- Fix off-by-one arithmetic so end > start (e.g. arange(lo, hi) with hi > lo)
- If size-0 kernels are legitimately needed, guard the kernel launch: skip grid steps where the block length would be 0
Example fix
// before
idx = jnp.arange(start, end) # end <= start crashes lowering
// after
if end > start:
idx = jnp.arange(start, end)
else:
idx = jnp.zeros((0,), dtype=jnp.int32) Defensive patterns
Strategy: validation
Validate before calling
def validate_ranges(n):
if not isinstance(n, int) or n < 1:
raise ValueError(f'dimension must be >= 1 for iota/arange on Triton, got {n}') Prevention
- Skip kernel launches for size-0 dimensions rather than relying on empty blocks
- Double-check slicing bounds so arange/loopy ranges always have end > start
When it happens
Trigger: A Pallas kernel grid/block specification yields a zero or negative-length range: e.g. an iota over a dimension of size 0, a block shape containing 0, or argreduce/iota where the computed start offset is >= end. Calling jnp.arange(a, b) with b <= a inside a Triton-lowered kernel also maps here.
Common situations: Dynamically computed block shapes that become 0 for degenerate inputs (empty batch); off-by-one bugs when slicing; passing a block dimension of 0 in pallas.BlockSpec; edge-case tests with size-0 arrays.
Related errors
- Cannot pull iota along dimension {dimension} with None block
- start and end must fit in int32
- unsupported cache modifier: {cache_modifier}
- unsupported eviction policy: {eviction_policy}
- unsupported pointer type: {ptr_type}
AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27).
Data as JSON: /api/errors/1416f4b4ff2d7e81.
Report an issue: GitHub.