sgl-project/sglang · error · RuntimeError

nvImageCodec returned an invalid JPEG tensor: shape={tuple(i

Error message

nvImageCodec returned an invalid JPEG tensor: shape={tuple(image.shape)}, dtype={image.dtype}

What it means

decode_jpeg_with_fancy_upsampling got a tensor back from nvImageCodec but it is not a 3D uint8 CHW tensor with 3 channels. The guard checks ndim==3, shape[0]==3, dtype==uint8, so grayscale (1 channel), RGBA (4 channels), or unexpected layouts/dtypes trigger this RuntimeError.

Source

Thrown at python/sglang/srt/utils/nvjpeg_decoder.py:82


@lru_cache(maxsize=None)
def _get_decoder_pool(device_id: int) -> _NvJpegDecoderPool:
    return _NvJpegDecoderPool(device_id)


def decode_jpeg_with_fancy_upsampling(image_bytes: bytes) -> torch.Tensor:
    """Decode a JPEG to contiguous CHW RGB uint8 on the current CUDA device.

    torchvision's CUDA JPEG decoder creates nvJPEG with its default flags,
    which use nearest-neighbor chroma upsampling. nvImageCodec exposes nvJPEG's
    interpolated ("fancy") upsampling and exports the result to PyTorch through
    DLPack without copying it.
    """
    device_id = torch.cuda.current_device()
    image = _get_decoder_pool(device_id).decode(image_bytes)
    if image.ndim != 3 or image.shape[0] != 3 or image.dtype != torch.uint8:
        raise RuntimeError(
            "nvImageCodec returned an invalid JPEG tensor: "
            f"shape={tuple(image.shape)}, dtype={image.dtype}"
        )
    return image

View on GitHub (pinned to 0132848349)

Solutions

  1. Convert grayscale inputs to RGB before submission (PIL convert('RGB')) or pre-check the JPEG component count
  2. Add a try/except with CPU fallback that normalizes to RGB
  3. Pin/verify the nvImageCodec version and decode params (output color format) used by the pool

Example fix

# before
img = decode_jpeg_with_fancy_upsampling(data)  # grayscale JPEG -> RuntimeError
# after
try:
    img = decode_jpeg_with_fancy_upsampling(data)
except RuntimeError:
    img = cpu_decode_rgb(data)
Defensive patterns

Strategy: try-catch

Validate before calling

def jpeg_channel_count(path) -> int:
    from PIL import Image
    with Image.open(path) as im:
        return len(im.getbands())

Type guard

null

Try / catch

try:
    img = decode_jpeg_with_fancy_upsampling(data)
except RuntimeError as e:
    if 'invalid JPEG tensor' in str(e):
        img = decode_with_pil(data).convert('RGB')
    else:
        raise

Prevention

When it happens

Trigger: Decoding a grayscale JPEG (nvImageCodec yields 1-channel), an image decoded to a non-standard layout, or a colorspace config mismatch in the decode params producing non-uint8 output.

Common situations: Datasets mixing RGB and grayscale JPEGs; images with unusual color spaces; version changes in nvImageCodec altering output layout.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/6075f16d8abd8c16. Report an issue: GitHub.