Describe the bug
perlin() returns a fully corrupted array when the input DataArray has an integer dtype. Every pixel ends up as INT_MIN (-2147483648 for int32).
_validate_raster() accepts integer dtypes, but all four perlin backends write float noise back into the user's buffer in place and then normalize by ptp. With an integer buffer the float noise (values in [-1, 1]) casts to 0, so ptp is 0, and (data - min) / ptp divides by zero. The NaN/Inf then casts back to int32 as INT_MIN.
Reproduction
import numpy as np
import xarray as xr
from xrspatial import perlin
data = np.zeros((20, 20), dtype=np.int32)
raster = xr.DataArray(data, dims=['y', 'x'])
result = perlin(raster)
print(result.data.min(), result.data.max())
# -2147483648 -2147483648
A RuntimeWarning fires but the corrupted result is still returned, so a caller who isn't watching warnings has no signal that anything went wrong.
Expected behavior
perlin() should raise ValueError on a non-floating-point DataArray. It's a generator that overwrites the raster in place, so integer storage doesn't make sense for it.
Affected backends
_perlin_numpy, _perlin_cupy, _perlin_dask_numpy, and _perlin_dask_cupy all use the same write-in-place-then-normalize pattern, so all four are affected.
Proposed fix
After _validate_raster(...) in perlin(), check agg.dtype and raise ValueError if it isn't floating-point.
Follow-up (not fixed here)
Even with float input, degenerate cases like freq=(0, 0) produce constant noise, which makes ptp zero and emits NaN through the same normalization. A zero-ptp guard would close that gap; tracking it separately.
Context
Found during the perlin security sweep on 2026-04-22 - Category 6 (Dtype Confusion), silent wrong results.
Describe the bug
perlin()returns a fully corrupted array when the input DataArray has an integer dtype. Every pixel ends up asINT_MIN(-2147483648 for int32)._validate_raster()accepts integer dtypes, but all four perlin backends write float noise back into the user's buffer in place and then normalize byptp. With an integer buffer the float noise (values in [-1, 1]) casts to 0, soptpis 0, and(data - min) / ptpdivides by zero. The NaN/Inf then casts back to int32 as INT_MIN.Reproduction
A RuntimeWarning fires but the corrupted result is still returned, so a caller who isn't watching warnings has no signal that anything went wrong.
Expected behavior
perlin()should raiseValueErroron a non-floating-point DataArray. It's a generator that overwrites the raster in place, so integer storage doesn't make sense for it.Affected backends
_perlin_numpy,_perlin_cupy,_perlin_dask_numpy, and_perlin_dask_cupyall use the same write-in-place-then-normalize pattern, so all four are affected.Proposed fix
After
_validate_raster(...)inperlin(), checkagg.dtypeand raiseValueErrorif it isn't floating-point.Follow-up (not fixed here)
Even with float input, degenerate cases like
freq=(0, 0)produce constant noise, which makesptpzero and emits NaN through the same normalization. A zero-ptp guard would close that gap; tracking it separately.Context
Found during the perlin security sweep on 2026-04-22 - Category 6 (Dtype Confusion), silent wrong results.