{"record":{"id":"9c24da374c94f1db","repo":"jax-ml/jax","slug":"for-valid-mode-one-input-must-be-at-least-as-la","errorCode":null,"errorMessage":"For 'valid' mode, One input must be at least as large as the other in every dimension.","messagePattern":"For 'valid' mode, One input must be at least as large as the other in every dimension\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/scipy/signal.py","lineNumber":129,"sourceCode":"  axes = tuple(canonicalize_axis(ax, in1.ndim) for ax in axes)\n  mapped_axes = set(range(in1.ndim)) - set(axes)\n  if any(in1.shape[i] != in2.shape[i] for i in mapped_axes):\n    raise ValueError(f\"mapped axes must have same shape; got {in1.shape=} {in2.shape=} {axes=}\")\n  for ax in sorted(mapped_axes):\n    _fftconvolve = api.vmap(_fftconvolve, in_axes=ax, out_axes=ax)\n  return _fftconvolve(in1, in2)\n\ndef _fftconvolve_unbatched(in1: Array, in2: Array, mode: str) -> Array:\n  full_shape = tuple(s1 + s2 - 1 for s1, s2 in zip(in1.shape, in2.shape))\n\n  # TODO(jakevdp): potentially use next_fast_len to evaluate with a more efficient shape.\n  fft_shape = full_shape  # tuple(next_fast_len(s) for s in full_shape)\n\n  if mode == 'valid':\n    no_swap = all(s1 >= s2 for s1, s2 in zip(in1.shape, in2.shape))\n    swap = all(s1 <= s2 for s1, s2 in zip(in1.shape, in2.shape))\n    if not (no_swap or swap):\n      raise ValueError(\"For 'valid' mode, One input must be at least as \"\n                       \"large as the other in every dimension.\")\n    if swap:\n      in1, in2 = in2, in1\n\n  if (all(s1 == 1 or s2 == 1 for s1, s2 in zip(in1.shape, in2.shape))):\n    conv = in1 * in2\n  else:\n    if jnp.iscomplexobj(in1):\n      fft, ifft = jnp.fft.fftn, jnp.fft.ifftn\n    else:\n      fft, ifft = jnp.fft.rfftn, jnp.fft.irfftn\n    sp1 = fft(in1, fft_shape)\n    sp2 = fft(in2, fft_shape)\n    conv = ifft(sp1 * sp2, fft_shape)\n\n  if mode == \"full\":\n    out_shape = full_shape\n  elif mode == \"same\":","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/scipy/signal.py#L111-L147","documentation":"For mode='valid', one input must dominate the other in every dimension (s1 >= s2 or s1 <= s2 consistently) so that a well-defined overlap region exists. Mixed ordering (bigger in one dim, smaller in another) is rejected.","triggerScenarios":"fftconvolve of shapes (10, 3) and (4, 5): first input larger in dim0 but smaller in dim1.","commonSituations":"2D filters where kernel size exceeds image size in one axis; mis-sized padding producing inconsistent shapes.","solutions":["Pad the smaller input so one operand dominates everywhere, or crop the larger one","Switch to mode='same' or 'full' if valid semantics aren't required","Verify kernel size <= input size per axis before calling"],"exampleFix":"# before\nsignal.fftconvolve(img, kernel, mode='valid')  # img (10,3), kernel (4,5)\n# after\nimg = jnp.pad(img, ((0,0),(0,2)))  # now (10,5)\nsignal.fftconvolve(img, kernel, mode='valid')","handlingStrategy":"validation","validationCode":"ok = all(s1 >= s2 for s1,s2 in zip(in1.shape,in2.shape)) or all(s1 <= s2 for s1,s2 in zip(in1.shape,in2.shape))\nassert ok","typeGuard":"def valid_mode_valid(a, b) -> bool:\n    return all(x >= y for x, y in zip(a.shape, b.shape)) or all(x <= y for x, y in zip(a.shape, b.shape))","tryCatchPattern":null,"preventionTips":["Assert kernel <= input per axis in your convolution wrapper"],"tags":["jax","scipy","signal","convolution","shape-mismatch"],"backgroundTag":"argument-shape-mismatch","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}