{"record":{"id":"8e36828566446b42","repo":"sgl-project/sglang","slug":"pair-postprocess-must-return-the-same-shape-as-inp","errorCode":null,"errorMessage":"pair_postprocess must return the same shape as input","messagePattern":"pair_postprocess must return the same shape as input","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py","lineNumber":521,"sourceCode":"            sigma_to = self.timestep_to_sigma(timestep_to)\n        prev_sample = sample + model_output * (sigma_to - sigma_from)\n        return prev_sample\n\n    def _refresh_pair_cache(self) -> None:\n        if self.timesteps is None or self.sigmas is None:\n            raise RuntimeError(\"Scheduler not initialized; call set_timesteps() first\")\n\n        def _apply_postprocess(pairs: torch.Tensor, source: str) -> torch.Tensor:\n            if self._pair_postprocess_fn is None:\n                return pairs\n            if self._pair_postprocess_requires_source:\n                modified = self._pair_postprocess_fn(pairs, source=source)\n            else:\n                modified = self._pair_postprocess_fn(pairs)\n            if not isinstance(modified, torch.Tensor):\n                raise TypeError(\"pair_postprocess must return a torch.Tensor\")\n            if modified.shape != pairs.shape:\n                raise ValueError(\"pair_postprocess must return the same shape as input\")\n            return modified\n\n        base_pairs_timesteps = self._make_pairs_from_vector(self.timesteps)\n        base_pairs_sigmas = self._make_pairs_from_vector(self.sigmas)\n\n        self.pair_timesteps = _apply_postprocess(base_pairs_timesteps, \"timesteps\")\n        self.pair_sigmas = _apply_postprocess(base_pairs_sigmas, \"sigmas\")\n\n\nEntryClass = FlowMatchPairScheduler\n","sourceCodeStart":503,"sourceCodeEnd":532,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py#L503-L532","documentation":"The pair_postprocess hook must preserve the input pair tensor's shape (it modifies values, not structure, of the (num_steps, 2) pairs). Returning a differently-shaped tensor breaks the cached pair schedule invariants.","triggerScenarios":"A postprocess that slices (pairs[:, 0]), stacks along the wrong dim, adds/removes steps, or returns the unstacked columns instead of the stacked pair tensor.","commonSituations":"Porting a single-vector sigma shift function that operates on 1D sigmas and forgetting to re-stack to (N, 2); off-by-one slicing to drop the terminal sigma.","solutions":["Return a tensor with identical .shape; if you modify columns, keep torch.stack([col0, col1], dim=1) as _dual_sigma_shift does","Log/assert modified.shape == pairs.shape in your hook during development","Model your hook on the built-in _dual_sigma_shift implementation"],"exampleFix":"# before\ndef pp(pairs, source):\n    return pairs[:, 0] * 2  # wrong shape\n# after\ndef pp(pairs, source):\n    return torch.stack([pairs[:, 0] * 2, pairs[:, 1] * 2], dim=1)","handlingStrategy":"validation","validationCode":"def pp(pairs, source):\n    out = modify(pairs)\n    assert out.shape == pairs.shape, (out.shape, pairs.shape)\n    return out","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Mirror the built-in _dual_sigma_shift stack pattern","Shape-assert inside hooks during development"],"tags":["scheduler","tensor-shape","callback"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}