{"record":{"id":"16c9715d8d914923","repo":"sgl-project/sglang","slug":"pair-postprocess-must-return-a-torch-tensor","errorCode":null,"errorMessage":"pair_postprocess must return a torch.Tensor","messagePattern":"pair_postprocess must return a torch\\.Tensor","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py","lineNumber":519,"sourceCode":"            )\n        else:\n            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":501,"sourceCodeEnd":532,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/models/schedulers/flow_match_pair.py#L501-L532","documentation":"A custom pair_postprocess callable must return a torch.Tensor; returning None, a numpy array, a tuple, or a list triggers this TypeError inside _apply_postprocess during cache refresh.","triggerScenarios":"Registering a hook via set_pair_postprocess that returns e.g. a numpy array, a (tensor, meta) tuple, or mutates in place and implicitly returns None.","commonSituations":"Adapting diffusers-style callback functions that return numpy; forgetting a return statement in a lambda-style postprocess.","solutions":["Make the callable return a torch.Tensor (convert with torch.from_numpy(...)/torch.as_tensor(...))","Ensure the function has an explicit return of the modified tensor","Check the callable is not writing results to a captured external variable instead of returning"],"exampleFix":"# before\ndef pp(pairs, source):\n    pairs = pairs.cpu().numpy() * 2  # returns ndarray\n# after\ndef pp(pairs, source):\n    return pairs * 2","handlingStrategy":"type-guard","validationCode":"out = fn(pairs)\nassert isinstance(out, torch.Tensor), type(out)","typeGuard":"def returns_tensor(fn, *a, **k) -> bool:\n    return isinstance(fn(*a, **k), torch.Tensor)","tryCatchPattern":null,"preventionTips":["Write hooks with an explicit `return tensor` statement","Convert numpy results with torch.from_numpy"],"tags":["scheduler","type-mismatch","callback"],"backgroundTag":"callback-return-type-invalid","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}