jax-ml/jax · error · IndexError
Out-of-bounds block index {block_indices} for input "{input_
Error message
Out-of-bounds block index {block_indices} for input "{input_name}" in iteration {grid_loop_idx} on device {device_id} (core {local_core_id}): reading [{read_range}] but input has shape {shape}. What it means
The Pallas TPU interpreter detected that, when copying a block of a pallas_call input into a kernel buffer before invoking the kernel body, the block's read range (start index + block shape) exceeds the input's actual shape. It reports which input, grid iteration, device, and core produced the violation.
Source
Thrown at jax/_src/pallas/mosaic/interpret/interpret_pallas_call.py:681
if (ret is None) or (tuple(full_read_shape) != ret.shape):
if shared_memory.out_of_bounds_reads == 'raise':
if source_info is None:
ctx = contextlib.nullcontext()
else:
ctx = source_info_util.user_context(
traceback=source_info.traceback, name_stack=source_info.name_stack
)
with ctx:
if input_name is None:
raise IndexError(
'Out-of-bounds read of'
f' ({device_id} {local_core_id} {memory_space} {buffer_id}):'
f' reading [{read_range}] but buffer has shape {shape}.'
)
else:
# Different error message when we are reading a block of an input,
# to copy it to a buffer before invoking the kernel body.
raise IndexError(
f'Out-of-bounds block index {block_indices} for'
f' input "{input_name}" in iteration {grid_loop_idx}'
f' on device {device_id} (core {local_core_id}):'
f' reading [{read_range}] but input has shape {shape}.'
)
# out_of_bounds_reads == "uninitialized"
uninit_array = np.full(
full_read_shape,
interpret_utils.get_uninitialized_value(
dtype, shared_memory.uninitialized_memory
),
dtype=dtype,
)
if ret is None:
ret = uninit_array
else:
uninit_array[tuple(slice(s) for s in ret.shape)] = ret
ret = uninit_arrayView on GitHub (pinned to 1e1c6a8fc0)
Solutions
- Ensure every input's BlockSpec yields exactly ceil(input.shape / block_shape) valid blocks matching the grid
- Pad smaller inputs so their block counts align with the grid
- Fix the index_map to clamp or correctly compute per-input block offsets
- Reproduce in interpret mode and inspect the reported block_indices and read_range vs the input shape
Example fix
# before in_spec = BlockSpec((BM,), lambda i: (i * BM,)) # grid too big for this input # after in_spec = BlockSpec((BM,), lambda i: (i * BM,)) grid = (x.shape[0] // BM,) # match grid to smallest valid block count (pad x if needed)
Defensive patterns
Strategy: validation
Validate before calling
import math
def check_blockspec(x, spec, grid):
n_blocks = math.ceil(x.shape[0] / spec.block_shape[0])
assert grid[0] <= n_blocks, f'grid {grid} exceeds {n_blocks} blocks for input shape {x.shape}' Try / catch
try:
kernel_grid_run(inputs)
except IndexError as e:
if 'Out-of-bounds block index' in str(e) and 'input' in str(e):
pad_and_retry() Prevention
- Derive grid from the smallest valid block count across all inputs
- Pad each input so its block count matches the grid
- Log BlockSpec index_map outputs during development
When it happens
Trigger: A pallas_call input with a BlockSpec whose block shape or index_map produces start indices such that start + block_shape > input.shape on some grid iteration; typical when the grid is larger than the number of valid blocks for that input.
Common situations: Multiple inputs with different sizes but a grid sized for the largest; non-divisible shapes without padding; index_map that scales program_id beyond the valid block count for one specific input.
Related errors
- Out-of-bounds block index {block_indices} for output "{outpu
- Out-of-bounds read of ({device_id} {local_core_id} {memory_s
- Out-of-bounds write of ({device_id} {local_core_id} {memory_
- Out-of-bounds swap of ({device_id} {local_core_id} {memory_s
- Out-of-bounds masked swap of ({device_id} {local_core_id} {m
AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27).
Data as JSON: /api/errors/4cff24ba83a35528.
Report an issue: GitHub.