{"record":{"id":"666759a9f2e91262","repo":"sgl-project/sglang","slug":"unsupported-pd-dcp-topology-self-dcp-size-d","errorCode":null,"errorMessage":"Unsupported PD DCP topology: {self.dcp_size} -> {dst_dcp_size}","messagePattern":"Unsupported PD DCP topology: (.+?) -> (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"python/sglang/srt/disaggregation/common/conn.py","lineNumber":325,"sourceCode":"        )\n\n    def requires_dcp_relayout(self, dst_dcp_size: int, dst_dcp_rank: int) -> bool:\n        if self.dcp_size == dst_dcp_size:\n            if self.dcp_rank != dst_dcp_rank:\n                raise RuntimeError(\n                    \"PD peers must connect matching DCP ranks, got \"\n                    f\"prefill={self.dcp_rank}, decode={dst_dcp_rank}\"\n                )\n            return False\n\n        if (\n            self.dcp_size == 1\n            and dst_dcp_size > 1\n            and (self.is_mla_backend or self.is_hybrid_mla_backend)\n        ):\n            return True\n\n        raise RuntimeError(\n            f\"Unsupported PD DCP topology: {self.dcp_size} -> {dst_dcp_size}\"\n        )\n\n    def prepare_dcp_token_item_lens(self, dst_page_item_lens: List[int]) -> List[int]:\n        page_size = self.kv_args.page_size\n        src_token_lens = [\n            item_len // page_size for item_len in self.kv_args.kv_item_lens\n        ]\n        dst_token_lens = [item_len // page_size for item_len in dst_page_item_lens]\n        if src_token_lens != dst_token_lens:\n            raise RuntimeError(\n                \"PD DCP source/destination KV geometry differs: \"\n                f\"src={src_token_lens}, dst={dst_token_lens}\"\n            )\n        return src_token_lens\n\n    def check_status(self, bootstrap_room: int) -> KVPoll:\n        return self.request_status[bootstrap_room]","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/disaggregation/common/conn.py#L307-L343","documentation":"requires_dcp_relayout returns whether KV must be relaid-out across DCP ranks between prefill and decode. Equal sizes pair 1:1 (no relayout) and 1->N with MLA backends can relayout; every other topology combination — notably N->1 or N->M — is unsupported and raises RuntimeError.","triggerScenarios":"PD disaggregation where decode DCP size differs from prefill DCP size and the pair is not (1 -> N with an MLA or hybrid-MLA backend), e.g. prefill --dcp-size 2 with decode --dcp-size 1, or 2 -> 4.","commonSituations":"Operator scales only one side of the PD cluster (adds CP ranks to prefill but not decode, or vice versa); reusing launch scripts with different tensor/context parallel settings per side; non-MLA backend combined with asymmetric DCP.","solutions":["Set the same --dcp-size (context-parallel size) on prefill and decode instances so ranks pair 1:1","If asymmetric sizes are required, keep prefill dcp_size == 1 and use an MLA (or hybrid MLA) backend so the 1->N relayout path applies","Otherwise re-topologize the cluster so sizes match; N->M and N->1 are not supported"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"ok = (dcp_size == dst_dcp_size) or (dcp_size == 1 and dst_dcp_size > 1 and is_mla_backend)\\nassert ok, f'unsupported PD DCP topology {dcp_size}->{dst_dcp_size}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run equal --dcp-size on prefill and decode","If asymmetric, keep prefill at dcp_size 1 with an MLA backend","Add a pre-launch topology check comparing both sides' parallel configs"],"tags":["disaggregation","dcp","topology","parallelism"],"backgroundTag":"unsupported-parallel-topology","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}