jax-ml/jax · error · ValueError

Breakpoints must be non-negative and less than length of dat

Error message

Breakpoints must be non-negative and less than length of data along given axis.

What it means

For linear detrending, breakpoints are combined with 0 and N (data length along axis) and must lie within [0, N]. A negative breakpoint or one exceeding the axis length raises this error, because piecewise fitting would reference nonexistent data.

Source

Thrown at jax/_src/scipy/signal.py:539

    >>> with jnp.printoptions(precision=3):  # suppress float error
    ...   print("Detrended:", detrended)
    ...   print("Underlying trend:", data - detrended)
    Detrended: [-5. -2.  2.  2.  3.]
    Underlying trend: [6. 6. 6. 6. 6.]
  """
  if overwrite_data is not None:
    raise NotImplementedError("overwrite_data argument not implemented.")
  if type not in ['constant', 'linear']:
    raise ValueError("Trend type must be 'linear' or 'constant'.")
  data_arr, = promote_dtypes_inexact(jnp.asarray(data))
  if type == 'constant':
    return data_arr - data_arr.mean(axis, keepdims=True)
  else:
    N = data_arr.shape[axis]
    # bp is static, so we use np operations to avoid pushing to device.
    bp_arr = np.sort(np.unique(np.r_[0, bp, N]))
    if bp_arr[0] < 0 or bp_arr[-1] > N:
      raise ValueError("Breakpoints must be non-negative and less than length of data along given axis.")
    data_arr = jnp.moveaxis(data_arr, axis, 0)
    shape = data_arr.shape
    data_arr = data_arr.reshape(N, -1)
    for m in range(len(bp_arr) - 1):
      Npts = bp_arr[m + 1] - bp_arr[m]
      A = jnp.vstack([
        jnp.ones(Npts, dtype=data_arr.dtype),
        jnp.arange(1, Npts + 1, dtype=data_arr.dtype) / Npts.astype(data_arr.dtype)
      ]).T
      sl = slice(bp_arr[m], bp_arr[m + 1])
      coef, *_ = linalg.lstsq(A, data_arr[sl])
      data_arr = data_arr.at[sl].add(-jnp.matmul(A, coef, precision=lax.Precision.HIGHEST))
    return jnp.moveaxis(data_arr.reshape(shape), 0, axis)


def _fft_helper(x: Array, win: Array, detrend_func: Callable[[Array], Array],
                nperseg: int, noverlap: int, nfft: int | None, sides: str) -> Array:
  """Calculate windowed FFT in the same way the original SciPy does.

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Clamp/validate breakpoints to 0 <= bp <= x.shape[axis] before calling
  2. Recompute breakpoints from the current data length (indices, not physical units)
  3. Verify the axis argument matches the axis the breakpoints were computed on

Example fix

// before
jax.scipy.signal.detrend(x, type='linear', bp=bps)
// after
N = x.shape[axis]
bps = [b for b in bps if 0 <= b <= N]
jax.scipy.signal.detrend(x, type='linear', bp=bps)
Defensive patterns

Strategy: validation

Validate before calling

N = x.shape[axis]
bp = [b for b in bp if 0 <= b <= N]
assert len(bp) > 0 or not bp, 'breakpoints filtered'

Prevention

When it happens

Trigger: detrend(x, type='linear', bp=[-2]) or bp=[50] on an axis of length 40; reusing breakpoints computed against a different (longer) dataset or after reshaping.

Common situations: Hardcoded breakpoint indices from earlier data; off-by-one after slicing; breakpoints derived from timestamps not sample indices.

Related errors


AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27). Data as JSON: /api/errors/bbb5ed3d05fecff8. Report an issue: GitHub.