{"record":{"id":"4fdf7e02450ff3de","repo":"sgl-project/sglang","slug":"self-transport-name-cannot-transport-an-empty-te","errorCode":null,"errorMessage":"{self.transport_name} cannot transport an empty tensor","messagePattern":"(.+?) cannot transport an empty tensor","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/multimodal/transport/memory_pool.py","lineNumber":339,"sourceCode":"                with self._lock, torch.cuda.device(self.device_id):\n                    self._recycle_ready_leases_locked()\n            except Exception:\n                logger.warning(\n                    \"%s multimodal pool recycle failed\",\n                    self.transport_name,\n                    exc_info=True,\n                )\n            self._recycler_stop_event.wait(self._recycle_interval)\n\n    def copy_tensor(\n        self, tensor: torch.Tensor\n    ) -> tuple[Optional[PoolLease], Optional[torch.Tensor]]:\n        if not tensor.is_cuda:\n            raise ValueError(f\"{self.transport_name} requires a CUDA tensor\")\n        source = tensor.contiguous()\n        nbytes = source.numel() * source.element_size()\n        if nbytes == 0:\n            raise ValueError(f\"{self.transport_name} cannot transport an empty tensor\")\n        with self._lock:\n            lease = self._allocate_locked(nbytes)\n        if lease is None:\n            return None, None\n\n        try:\n            with torch.cuda.device(self.device_id):\n                destination = self.byte_tensor[lease.start : lease.start + lease.nbytes]\n                destination.copy_(\n                    source.view(torch.uint8).reshape(-1), non_blocking=True\n                )\n                stream_write_value32(\n                    self.device_id,\n                    self.base_address + lease.ready_byte_offset,\n                    lease.generation,\n                    self.transport_name,\n                )\n        except Exception:","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/multimodal/transport/memory_pool.py#L321-L357","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Skip the copy when tensor.numel() == 0 at the call site","Fix upstream filtering so empty multimodal payloads don't reach the transport layer","Guard with a helper that returns None for empty tensors"],"exampleFix":"# before\nlease, view = pool.copy_tensor(tensor)\n# after\nlease, view = (None, None) if tensor.numel() == 0 else pool.copy_tensor(tensor)","handlingStrategy":"validation","validationCode":"if tensor.numel() == 0:\n    return None, None  # skip transport for empty tensors\nlease, view = pool.copy_tensor(tensor)","typeGuard":"def is_transportable(t: torch.Tensor) -> bool:\n    return t.is_cuda and t.numel() * t.element_size() > 0","tryCatchPattern":null,"preventionTips":["Filter empty multimodal payloads before the transport layer","Treat zero-element tensors as 'nothing to send' in batch assembly"],"tags":["multimodal","empty-tensor","validation"],"backgroundTag":"empty-tensor-input","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}