sgl-project/sglang · error · ValueError
pairs must be a torch.Tensor of shape [N, 2]
Error message
pairs must be a torch.Tensor of shape [N, 2]
What it means
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().
Source
Thrown at python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py:260
- amp: Float amplitude, default 150.0.
Raises:
ValueError: If name is unknown.
"""
if name is None or str(name).lower() in ("none", "off", "false", "no"):
self.set_pair_postprocess(None)
return
if name == "quadratic_perp_bulge_swap":
amp = float(kwargs.get("amp", 150.0))
def _quadratic_perp_bulge_swap(pairs: torch.Tensor):
if (
not isinstance(pairs, torch.Tensor)
or pairs.ndim != 2
or pairs.shape[1] != 2
):
raise ValueError("pairs must be a torch.Tensor of shape [N, 2]")
x = pairs[:, 0]
T = float(self.num_train_timesteps)
s = x / T
d = 4.0 * amp * s * (1.0 - s)
x2 = x + d
y2 = x - d
return torch.stack([x2, y2], dim=1)
self.set_pair_postprocess(_quadratic_perp_bulge_swap)
return
if name == "v2a_sequential":
def _v2a(pairs: torch.Tensor):
if (
not isinstance(pairs, torch.Tensor)
or pairs.ndim != 2
or pairs.shape[1] != 2
):View on GitHub (pinned to 0132848349)
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
Example fix
// before timesteps = scheduler.set_timesteps(num_steps) # returns flat [N] # after timesteps = scheduler.set_timesteps(num_steps) pairs = torch.stack([timesteps, timesteps], dim=1) # [N, 2]
Defensive patterns
Strategy: type-guard
Validate before calling
def valid_pairs(p) -> bool:
return isinstance(p, torch.Tensor) and p.ndim == 2 and p.shape[1] == 2 Type guard
def is_pairs_tensor(p) -> TypeGuard[torch.Tensor]:
return isinstance(p, torch.Tensor) and p.ndim == 2 and p.shape[1] == 2 Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- `dt_bias` must have {HV * K} elements (got {dt_bias.numel()}
- `mixed_qkv` must be 2D (got ndim={mixed_qkv.ndim}).
- pairs must be a torch.Tensor
- pairs length must be greater than 0
- denoising_strength must be positive
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/3c92d1c6b794ac51.
Report an issue: GitHub.