sgl-project/sglang · error · ValueError

{self.transport_name} cannot transport an empty tensor

Error message

{self.transport_name} cannot transport an empty tensor

What it means

An empty tensor (0 bytes) has nothing to transport and would produce a zero-length lease/slot pairing that downstream consumers cannot distinguish, so copy_tensor rejects nbytes == 0.

Source

Thrown at python/sglang/srt/multimodal/transport/memory_pool.py:339

                with self._lock, torch.cuda.device(self.device_id):
                    self._recycle_ready_leases_locked()
            except Exception:
                logger.warning(
                    "%s multimodal pool recycle failed",
                    self.transport_name,
                    exc_info=True,
                )
            self._recycler_stop_event.wait(self._recycle_interval)

    def copy_tensor(
        self, tensor: torch.Tensor
    ) -> tuple[Optional[PoolLease], Optional[torch.Tensor]]:
        if not tensor.is_cuda:
            raise ValueError(f"{self.transport_name} requires a CUDA tensor")
        source = tensor.contiguous()
        nbytes = source.numel() * source.element_size()
        if nbytes == 0:
            raise ValueError(f"{self.transport_name} cannot transport an empty tensor")
        with self._lock:
            lease = self._allocate_locked(nbytes)
        if lease is None:
            return None, None

        try:
            with torch.cuda.device(self.device_id):
                destination = self.byte_tensor[lease.start : lease.start + lease.nbytes]
                destination.copy_(
                    source.view(torch.uint8).reshape(-1), non_blocking=True
                )
                stream_write_value32(
                    self.device_id,
                    self.base_address + lease.ready_byte_offset,
                    lease.generation,
                    self.transport_name,
                )
        except Exception:

View on GitHub (pinned to 0132848349)

Solutions

  1. Skip the copy when tensor.numel() == 0 at the call site
  2. Fix upstream filtering so empty multimodal payloads don't reach the transport layer
  3. Guard with a helper that returns None for empty tensors

Example fix

# before
lease, view = pool.copy_tensor(tensor)
# after
lease, view = (None, None) if tensor.numel() == 0 else pool.copy_tensor(tensor)
Defensive patterns

Strategy: validation

Validate before calling

if tensor.numel() == 0:
    return None, None  # skip transport for empty tensors
lease, view = pool.copy_tensor(tensor)

Type guard

def is_transportable(t: torch.Tensor) -> bool:
    return t.is_cuda and t.numel() * t.element_size() > 0

Prevention

When it happens

Trigger: Passing a tensor with numel 0 (e.g. an empty batch of image patches, a sliced tensor that became empty after filtering) to wrap_tensor/copy_tensor.

Common situations: Batch filtering removes all multimodal items for a request but the transport call still runs; edge-case inputs like zero-size videos or empty feature lists.

Related errors


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