sgl-project/sglang · error · RuntimeError

nvImageCodec could not decode the JPEG image

Error message

nvImageCodec could not decode the JPEG image

What it means

The pooled nvImageCodec decoder returned None from decode() for a JPEG byte buffer, meaning the GPU JPEG decoder could not decode the payload. The wrapper converts this into a RuntimeError so callers can fall back to CPU decoding.

Source

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

                    max_num_cpu_threads=1,
                    options=_DECODER_OPTIONS,
                )
                self._created += 1
                return decoder

        return self._decoders.get()

    def decode(self, image_bytes: bytes) -> torch.Tensor:
        decoder = self._acquire()
        try:
            stream = torch.cuda.current_stream(self._device_id)
            image = decoder.decode(
                image_bytes,
                params=self._decode_params,
                cuda_stream=stream.cuda_stream,
            )
            if image is None:
                raise RuntimeError("nvImageCodec could not decode the JPEG image")
            return torch.from_dlpack(image.to_dlpack(cuda_stream=stream.cuda_stream))
        finally:
            self._decoders.put(decoder)


@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.
    """

View on GitHub (pinned to 0132848349)

Solutions

  1. Catch RuntimeError and fall back to a CPU decoder (PIL/torchvision) for that image
  2. Validate/skip corrupt images upstream (SOI/EOI markers, PIL verify)
  3. Check CUDA health if all decodes suddenly fail (reset pool, restart worker)
  4. Upgrade nvImageCodec if a specific JPEG variant is unsupported

Example fix

# before
img = decode_jpeg_with_fancy_upsampling(data)
# after
try:
    img = decode_jpeg_with_fancy_upsampling(data)
except RuntimeError:
    img = cpu_decode_jpeg(data)  # PIL/torchvision fallback
Defensive patterns

Strategy: fallback

Validate before calling

def looks_like_jpeg(data: bytes) -> bool:
    return len(data) > 4 and data[0:2] == b'\xff\xd8' and b'\xff\xd9' in data[-64:]

Type guard

null

Try / catch

try:
    tensor = decode_jpeg_with_fancy_upsampling(data)
except RuntimeError:
    tensor = decode_with_pil(data)  # CPU fallback

Prevention

When it happens

Trigger: Calling decode() on corrupted/truncated JPEG bytes, unsupported JPEG variants (e.g. CMYK, progressive with odd sampling), or when the NVJPEG handle is in a bad state after a prior CUDA error.

Common situations: Multimodal image pipelines feeding user-uploaded or URL-fetched images where some are truncated; GPU memory pressure or stale decoder state after CUDA errors.

Related errors


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