{"record":{"id":"7395bf178e1ce88e","repo":"jax-ml/jax","slug":"indices-must-have-an-integer-type","errorCode":null,"errorMessage":"indices must have an integer type","messagePattern":"indices must have an integer type","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/lax/slicing.py","lineNumber":1774,"sourceCode":"    ur_rule=_dynamic_update_slice_ur_rule)\nad.primitive_jvps[dynamic_update_slice_p] = _dynamic_update_slice_jvp\nad.primitive_transposes[dynamic_update_slice_p] = \\\n    _dynamic_update_slice_transpose_rule\nbatching.primitive_batchers[dynamic_update_slice_p] = \\\n    _dynamic_update_slice_batching_rule\n\ndef _dynamic_update_slice_lower(ctx, x, update, *start_indices):\n  aval_out, = ctx.avals_out\n  out = mlir.dynamic_update_slice(ctx, aval_out, x, update,\n                                  start_indices=start_indices)\n  return [mlir.lower_with_sharding_in_types(ctx, out, aval_out)]\n\nmlir.register_lowering(dynamic_update_slice_p, _dynamic_update_slice_lower)\n\n\ndef _gather_dtype_rule(operand, indices, *, fill_value, **kwargs):\n  if not dtypes.issubdtype(indices.dtype, np.integer):\n    raise ValueError(\"indices must have an integer type\")\n  return operand.dtype\n\n_rank = lambda arr: len(arr.shape)\n\ndef _is_sorted(dims, op_name, name):\n  for i in range(1, len(dims)):\n    if dims[i] < dims[i - 1]:\n      raise TypeError(f\"{name} in {op_name} op must be sorted; got {dims}\")\n\ndef _dims_in_range(dims, rank, op_name, name):\n  for dim in dims:\n    if dim < 0 or dim >= rank:\n      raise TypeError(f\"Invalid {name} set in {op_name} op; valid range is \"\n                      f\"[0, {rank}); got: {dim}.\")\n\ndef _sorted_dims_in_range(dims, rank, op_name, name):\n  if len(dims) == 0:\n    return","sourceCodeStart":1756,"sourceCodeEnd":1792,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/lax/slicing.py#L1756-L1792","documentation":"The dtype rule of lax.gather requires the indices array to have an integer dtype. Passing float (or other non-integer) indices raises this ValueError before any gathering occurs, since gather offsets must be integral. The operand dtype is returned unchanged when indices are valid.","triggerScenarios":"Calling lax.gather(operand, indices, dimension_numbers, slice_sizes, ...) where indices is a float array (e.g. from normalized coordinates, division, or interpolation). Also hit via jnp.take-like code paths that lower to gather with float index tensors.","commonSituations":"Image resampling / bilinear sampling code computing pixel coordinates in float32; feeding model outputs (float logits) directly as positions; forgetting to cast positions from float32 to int32 after coordinate arithmetic.","solutions":["Cast indices to an integer dtype: indices = indices.astype(jnp.int32).","For sub-pixel / fractional coordinates use interpolation utilities (e.g. jax.scipy.ndimage.map_coordinates) instead of gather.","Round before casting if coordinates are fractional: jnp.round(coords).astype(jnp.int32)."],"exampleFix":"# before\ncoords = jnp.array([[1.5, 2.5], [0.1, 3.9]])\nout = lax.gather(img, coords, dnums, slice_sizes=(1, 1))  # ValueError\n\n# after\ncoords = jnp.round(coords).astype(jnp.int32)\nout = lax.gather(img, coords, dnums, slice_sizes=(1, 1))","handlingStrategy":"type-guard","validationCode":"if not jnp.issubdtype(indices.dtype, jnp.integer):\n    indices = indices.astype(jnp.int32)","typeGuard":"def are_integer_indices(indices: jax.Array) -> bool:\n    return jnp.issubdtype(indices.dtype, jnp.integer)","tryCatchPattern":null,"preventionTips":["Cast coordinate tensors to int32 right after any float arithmetic (round if fractional).","For sub-pixel sampling use jax.scipy.ndimage.map_coordinates rather than gather."],"tags":["jax","lax","gather","dtype"],"backgroundTag":"dtype-mismatch-indices","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}