{"record":{"id":"3c92d1c6b794ac51","repo":"sgl-project/sglang","slug":"pairs-must-be-a-torch-tensor-of-shape-n-2","errorCode":null,"errorMessage":"pairs must be a torch.Tensor of shape [N, 2]","messagePattern":"pairs must be a torch\\.Tensor of shape \\[N, 2\\]","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py","lineNumber":260,"sourceCode":"                - amp: Float amplitude, default 150.0.\n\n        Raises:\n            ValueError: If name is unknown.\n        \"\"\"\n\n        if name is None or str(name).lower() in (\"none\", \"off\", \"false\", \"no\"):\n            self.set_pair_postprocess(None)\n            return\n        if name == \"quadratic_perp_bulge_swap\":\n            amp = float(kwargs.get(\"amp\", 150.0))\n\n            def _quadratic_perp_bulge_swap(pairs: torch.Tensor):\n                if (\n                    not isinstance(pairs, torch.Tensor)\n                    or pairs.ndim != 2\n                    or pairs.shape[1] != 2\n                ):\n                    raise ValueError(\"pairs must be a torch.Tensor of shape [N, 2]\")\n                x = pairs[:, 0]\n                T = float(self.num_train_timesteps)\n                s = x / T\n                d = 4.0 * amp * s * (1.0 - s)\n                x2 = x + d\n                y2 = x - d\n                return torch.stack([x2, y2], dim=1)\n\n            self.set_pair_postprocess(_quadratic_perp_bulge_swap)\n            return\n        if name == \"v2a_sequential\":\n\n            def _v2a(pairs: torch.Tensor):\n                if (\n                    not isinstance(pairs, torch.Tensor)\n                    or pairs.ndim != 2\n                    or pairs.shape[1] != 2\n                ):","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py#L242-L278","documentation":"The 'quadratic_perp_bulge_swap' pair postprocess in FlowMatchPairScheduler requires its input to be a 2-D torch.Tensor with exactly 2 columns (one value per modality: [t, t]). The guard raises ValueError when the tensor is missing, is not a torch.Tensor, is 1-D/3-D, or has shape[1] != 2. It is thrown inside the closure installed by set_pair_postprocess_by_name('quadratic_perp_bulge_swap'), which is invoked on the timestep/sigma pairs produced by set_timesteps().","triggerScenarios":"Calling set_pair_postprocess_by_name('quadratic_perp_bulge_swap', amp=...) and then set_timesteps()/refresh path where the cached pairs tensor is a flat 1-D tensor (e.g. a plain timestep linspace not reshaped to [N,2]), a list/numpy array, or a [N,1]/[N,3] tensor.","commonSituations":"Scheduler was constructed or initialized by code that predates the paired (dual-modality) API and still supplies single-column timesteps; custom model runners passing a Python list or numpy array instead of torch.Tensor; reshaping step (view(-1,2)/unsqueeze) omitted after migrating to joint audio-visual scheduling.","solutions":["Ensure the pairs tensor passed to the postprocess is created via torch.stack([t, t], dim=1) or .view(-1, 2) so it is [N, 2]","If integrating with legacy single-timestep code, wrap the 1-D tensor: pairs = t.unsqueeze(1).expand(-1, 2).contiguous()","Verify the value is actually a torch.Tensor (convert numpy with torch.from_numpy(...)) before the scheduler caches it","Disable the postprocess via set_pair_postprocess_by_name(None) if pair reshaping is not needed for your run"],"exampleFix":"// before\ntimesteps = scheduler.set_timesteps(num_steps)  # returns flat [N]\n\n# after\ntimesteps = scheduler.set_timesteps(num_steps)\npairs = torch.stack([timesteps, timesteps], dim=1)  # [N, 2]","handlingStrategy":"type-guard","validationCode":"def valid_pairs(p) -> bool:\n    return isinstance(p, torch.Tensor) and p.ndim == 2 and p.shape[1] == 2","typeGuard":"def is_pairs_tensor(p) -> TypeGuard[torch.Tensor]:\n    return isinstance(p, torch.Tensor) and p.ndim == 2 and p.shape[1] == 2","tryCatchPattern":null,"preventionTips":["Always construct pairs with torch.stack([t, t], dim=1), never pass a flat schedule","Assert pairs.ndim == 2 and pairs.shape[1] == 2 right after building the tensor"],"tags":["pytorch","tensor-shape","flow-matching","scheduler","validation"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}