{"record":{"id":"3b3743dc4ec05b83","repo":"sgl-project/sglang","slug":"grafter-tags-tags-matched-both-grafter-b2t-fil","errorCode":null,"errorMessage":"[Grafter] tags={tags} matched BOTH grafter_b2t_filter and grafter_t2b_filter","messagePattern":"\\[Grafter\\] tags=(.+?) matched BOTH grafter_b2t_filter and grafter_t2b_filter","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/debug_utils/dumper.py","lineNumber":964,"sourceCode":"                f\"before_overridden={info_before_overridden} \"\n                f\"to_override={get_tensor_info(value_to_override)} \"\n                f\"diff_pre_vs_new={diff}\"\n            )\n            value.copy_(value_to_override)\n        except Exception as e:\n            _log(\n                f\"[Grafter] recv role={role.value} dir={direction.value} \"\n                f\"tags={tags} transform/copy_ raised {type(e).__name__}: {e}; \"\n                f\"skipping graft for this call (target tensor unchanged)\\n\"\n                f\"{traceback.format_exc()}\"\n            )\n\n    def _classify_direction(self, tags: dict) -> Optional[\"_GraftDirection\"]:\n        cfg = self._config\n        match_b2t = self._match(cfg.grafter_b2t_filter, tags)\n        match_t2b = self._match(cfg.grafter_t2b_filter, tags)\n        if match_b2t and match_t2b:\n            raise RuntimeError(\n                f\"[Grafter] tags={tags} matched BOTH grafter_b2t_filter and grafter_t2b_filter\"\n            )\n        if match_b2t:\n            return _GraftDirection.B2T\n        if match_t2b:\n            return _GraftDirection.T2B\n        return None\n\n    @staticmethod\n    def _is_sender(*, role: \"_GraftRole\", direction: \"_GraftDirection\") -> bool:\n        # baseline is the sender for B2T names; target is the sender for T2B.\n        return (role == _GraftRole.BASELINE) == (direction == _GraftDirection.B2T)\n\n    def _sender_slice(self, *, direction: \"_GraftDirection\", gathered: list) -> list:\n        cfg = self._config\n        if direction == _GraftDirection.B2T:\n            return gathered[: cfg.grafter_baseline_world_size]\n        return gathered[cfg.grafter_baseline_world_size :]","sourceCodeStart":946,"sourceCodeEnd":982,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/debug_utils/dumper.py#L946-L982","documentation":"The Grafter can interpose data flowing bottom-to-top (B2T) or top-to-bottom (T2B), chosen by tag filters. If a tag dict matches BOTH grafter_b2t_filter and grafter_t2b_filter, direction is ambiguous and the grafter aborts with a RuntimeError to avoid grafting in the wrong direction.","triggerScenarios":"Configuring grafter_b2t_filter={'phase': 'decode'} and grafter_t2b_filter={'phase': 'decode'} (or overlapping patterns) so maybe_intercept's _classify_direction matches both for some tensor's tags.","commonSituations":"Copy-pasting one filter as the start of the other and editing incompletely; overly broad filters like {} (match-all) on both channels.","solutions":["Make the filters mutually exclusive, e.g. disjoint tag values per direction","Avoid empty/wildcard filters that match every tag dict","Test with a single tagged tensor and assert exactly one direction matches before running the full model"],"exampleFix":"# before\ncfg.grafter_b2t_filter = {\"phase\": \"decode\"}\ncfg.grafter_t2b_filter = {\"phase\": \"decode\"}\n# after\ncfg.grafter_b2t_filter = {\"phase\": \"decode\", \"dir\": \"up\"}\ncfg.grafter_t2b_filter = {\"phase\": \"decode\", \"dir\": \"down\"}","handlingStrategy":"validation","validationCode":"def _matches(filt, tags):\n    return all(tags.get(k) == v for k, v in (filt or {}).items())\nprobe_tags = {\"phase\": \"decode\", \"dir\": \"up\"}\nassert not (_matches(cfg.grafter_b2t_filter, probe_tags) and _matches(cfg.grafter_t2b_filter, probe_tags))","typeGuard":null,"tryCatchPattern":"try:\n    grafter.maybe_intercept(tags)\nexcept RuntimeError as e:\n    if \"matched BOTH\" in str(e):\n        # fix filters to be disjoint, then retry\n        ...","preventionTips":["Design filters over a disjoint tag dimension (e.g. 'dir')","Never set both filters to {} (match-all)"],"tags":["distributed","grafter","filter-config"],"backgroundTag":"ambiguous-config-match","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}