2026, Jan 12 05:00

How to fix CUDNN_STATUS_NOT_SUPPORTED in CuPy on CUDA 11.4 with cuDNN 8.4: switch to setConvolution2dDescriptor_v5

Resolve CUDNN_STATUS_NOT_SUPPORTED in CuPy on CUDA 11.4 with cuDNN 8.4 by using setConvolution2dDescriptor_v5 and computeType. Includes repro and fix.

Fixing cuDNN CUDNN_STATUS_NOT_SUPPORTED in CuPy with CUDA 11.4 and cuDNN 8.4

When wiring up cuDNN through CuPy on systems pinned to CUDA 11.4, you might hit CUDNN_STATUS_NOT_SUPPORTED as soon as you configure a convolution descriptor. In a setup with CPython 3.10.16, CuPy 10.6.0, CUDA runtime 11040 and cuDNN 8400, the error reproduced during a simple 2D convolution descriptor configuration.

Reproducible code that triggers the error

The example below initializes tensor/filter/conv descriptors and queries the forward output shape. The failure happens at the descriptor setup stage.

import cupy as xp
import cupy.cuda.cudnn as cu
print(xp.__version__)
print(xp.cuda.runtime.runtimeGetVersion())
print(xp.cuda.cudnn.getVersion())
def cudnn_conv2d_demo(arr2d: xp.ndarray, filt2d: xp.ndarray, b: xp.ndarray,
                      padding: int = 1, stride: int = 1):
    if arr2d.ndim != 2 or filt2d.ndim != 2 or b.ndim != 1:
        raise ValueError("arr2d, filt2d, and b must be 2D, 2D, and 1D respectively.")
    x4 = arr2d[xp.newaxis, xp.newaxis, :, :]
    w4 = filt2d[xp.newaxis, xp.newaxis, :, :]
    handle = cu.create()
    x_desc = cu.createTensorDescriptor()
    w_desc = cu.createFilterDescriptor()
    y_desc = cu.createTensorDescriptor()
    n, c, h, w = x4.shape
    k, _, kh, kw = w4.shape
    cu.setTensor4dDescriptor(
        x_desc,
        cu.CUDNN_TENSOR_NCHW,
        cu.CUDNN_DATA_FLOAT,
        n, c, h, w,
    )
    cu.setFilter4dDescriptor_v4(
        w_desc,
        cu.CUDNN_DATA_FLOAT,
        cu.CUDNN_TENSOR_NCHW,
        k, c, kh, kw,
    )
    conv_desc = cu.createConvolutionDescriptor()
    # This call leads to CUDNN_STATUS_NOT_SUPPORTED under cuDNN 8.4 in this setup
    cu.setConvolution2dDescriptor_v4(
        conv_desc,
        pad_h=padding,
        pad_w=padding,
        u=stride,
        v=stride,
        dilation_h=1,
        dilation_w=1,
        mode=cu.CUDNN_CONVOLUTION,
    )
    n2, c2, h2, w2 = cu.getConvolution2dForwardOutputDim(
        conv_desc,
        x_desc,
        w_desc,
    )
    y = xp.empty((n2, c2, h2, w2), dtype=xp.float32)
    cu.setTensor4dDescriptor(
        y_desc,
        cu.CUDNN_TENSOR_NCHW,
        cu.CUDNN_DATA_FLOAT,
        n2, c2, h2, w2,
    )
    return y[0, 0, :, :]
x2 = xp.array(
    [
        [0.0, 1.0, 2.0, 3.0],
        [4.0, 5.0, 0.0, 7.0],
        [4.0, 0.0, 6.0, 7.0],
        [0.0, 1.0, 2.0, 3.0],
    ],
    dtype=xp.float32,
)
w2 = xp.array(
    [[-3.0, -2.0, 1.0], [0.0, 1.0, 2.0], [-3.0, 0.0, 1.0]], dtype=xp.float32
)
bvec = xp.array([2.0], dtype=xp.float32)
pad_sz = 1
step = 1
print(cudnn_conv2d_demo.__name__)
res = cudnn_conv2d_demo(x2, w2, bvec, pad_sz, step)
print(f"{res}, shape is {res.shape}")

What is actually going on

In cuDNN 8.4, the generic cudnnSetConvolution2dDescriptor() symbol you might expect is not exposed the same way in the CuPy bindings. Instead there are versioned variants, including setConvolution2dDescriptor_v4 and setConvolution2dDescriptor_v5. The v4 variant does not accept a computeType parameter, while the v5 variant does. Calling the v4 function in this environment led to cuDNN returning CUDNN_STATUS_NOT_SUPPORTED. The cuDNN debug log shows descriptor creation calls followed by an error status, matching the observed exception.

The fix

Switch the call to the v5 variant and provide computeType explicitly. This aligns the call signature with what cuDNN expects here and removes the error.

import cupy as xp
import cupy.cuda.cudnn as cu
def cudnn_conv2d_fixed(arr2d: xp.ndarray, filt2d: xp.ndarray, b: xp.ndarray,
                       padding: int = 1, stride: int = 1):
    if arr2d.ndim != 2 or filt2d.ndim != 2 or b.ndim != 1:
        raise ValueError("arr2d, filt2d, and b must be 2D, 2D, and 1D respectively.")
    x4 = arr2d[xp.newaxis, xp.newaxis, :, :]
    w4 = filt2d[xp.newaxis, xp.newaxis, :, :]
    handle = cu.create()
    x_desc = cu.createTensorDescriptor()
    w_desc = cu.createFilterDescriptor()
    y_desc = cu.createTensorDescriptor()
    n, c, h, w = x4.shape
    k, _, kh, kw = w4.shape
    cu.setTensor4dDescriptor(
        x_desc,
        cu.CUDNN_TENSOR_NCHW,
        cu.CUDNN_DATA_FLOAT,
        n, c, h, w,
    )
    cu.setFilter4dDescriptor_v4(
        w_desc,
        cu.CUDNN_DATA_FLOAT,
        cu.CUDNN_TENSOR_NCHW,
        k, c, kh, kw,
    )
    conv_desc = cu.createConvolutionDescriptor()
    # Use v5 and pass computeType
    cu.setConvolution2dDescriptor_v5(
        conv_desc,
        pad_h=padding,
        pad_w=padding,
        u=stride,
        v=stride,
        dilation_h=1,
        dilation_w=1,
        mode=cu.CUDNN_CONVOLUTION,
        computeType=cu.CUDNN_DATA_FLOAT,
    )
    n2, c2, h2, w2 = cu.getConvolution2dForwardOutputDim(
        conv_desc,
        x_desc,
        w_desc,
    )
    y = xp.empty((n2, c2, h2, w2), dtype=xp.float32)
    cu.setTensor4dDescriptor(
        y_desc,
        cu.CUDNN_TENSOR_NCHW,
        cu.CUDNN_DATA_FLOAT,
        n2, c2, h2, w2,
    )
    return y[0, 0, :, :]

With setConvolution2dDescriptor_v5 and computeType set to CUDNN_DATA_FLOAT, the CUDNN_STATUS_NOT_SUPPORTED error no longer occurs.

Why this matters

cuDNN evolves, and function signatures can differ by minor version. CuPy exposes versioned symbols such as setConvolution2dDescriptor_v4 and setConvolution2dDescriptor_v5, and picking the wrong variant may lead to confusing NOT_SUPPORTED errors even when tensor shapes and formats look fine. Verifying the runtime versions through CuPy (for example 10.6.0 for CuPy, 11040 for CUDA, and 8400 for cuDNN) and checking which functions are present helps align code with the right API surface.

Takeaways

If you see CUDNN_STATUS_NOT_SUPPORTED while setting up convolution descriptors on cuDNN 8.4 via CuPy on CUDA 11.4, use the v5 descriptor function and provide computeType. When working across cuDNN releases, confirm available function variants at runtime and cross-reference the cuDNN documentation archives for the exact signature used by your version.