{"record":{"id":"2867c829a1fe2148","repo":"sgl-project/sglang","slug":"vision-tp-size-and-tp-rank-must-be-set-together","errorCode":null,"errorMessage":"Vision tp_size and tp_rank must be set together","messagePattern":"Vision tp_size and tp_rank must be set together","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/models/qwen3_vl.py","lineNumber":116,"sourceCode":"_is_cpu = is_cpu()\n\n# Below this image count the per-image loop beats the vectorized path (which has a\n# fixed setup cost; measured crossover ~6 on H20); both give the same result.\n_VECTORIZED_VL_POS_EMBED_MIN_IMAGES = 6\n\n\ndef _resolve_vision_tp(\n    *,\n    use_data_parallel: bool,\n    tp_size: Optional[int],\n    tp_rank: Optional[int],\n) -> tuple[int, int]:\n    if use_data_parallel:\n        if tp_size is not None or tp_rank is not None:\n            raise ValueError(\"Explicit vision TP cannot be combined with data parallel\")\n        return 1, 0\n    if (tp_size is None) != (tp_rank is None):\n        raise ValueError(\"Vision tp_size and tp_rank must be set together\")\n    if tp_size is None:\n        parallel = get_parallel()\n        return parallel.attn_tp_size, parallel.attn_tp_rank\n    assert tp_rank is not None\n    return tp_size, tp_rank\n\n\nclass Qwen3_VisionMLP(nn.Module):\n\n    def __init__(\n        self,\n        in_features: int,\n        hidden_features: int,\n        bias: bool = True,\n        hidden_act=\"silu\",\n        quant_config: Optional[QuantizationConfig] = None,\n        prefix: str = \"\",\n        use_data_parallel: bool = False,","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/models/qwen3_vl.py#L98-L134","documentation":"When overriding Qwen3-VL vision tensor parallelism you must supply both tp_size and tp_rank; supplying only one is rejected because the pair is meaningless alone.","triggerScenarios":"Constructing the vision tower with tp_size set but tp_rank None (or vice versa).","commonSituations":"Custom integration code partially specifying vision TP; forgetting the rank when wiring a distributed launcher.","solutions":["Pass both tp_size and tp_rank together","Or pass neither to fall back to attn_tp_size/attn_tp_rank from get_parallel()"],"exampleFix":"# before\n_resolve_vision_tp(use_data_parallel=False, tp_size=4, tp_rank=None)\n# after\n_resolve_vision_tp(use_data_parallel=False, tp_size=4, tp_rank=0)","handlingStrategy":"type-guard","validationCode":"assert (tp_size is None) == (tp_rank is None), \"set both or neither\"","typeGuard":"def valid_vision_tp(tp_size, tp_rank) -> bool:\n    return (tp_size is None and tp_rank is None) or (tp_size is not None and tp_rank is not None)","tryCatchPattern":null,"preventionTips":["Pass TP size and rank as an atomic pair"],"tags":["qwen3-vl","vision","tensor-parallel","argument-validation"],"backgroundTag":"partial-argument-pair","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}