{"record":{"id":"52862f75a441071c","repo":"sgl-project/sglang","slug":"validate-failed-s-s-must-be-divisible-by-f-f","errorCode":null,"errorMessage":"Validate failed: S({S}) must be divisible by F({F}).","messagePattern":"Validate failed: S\\((.+?)\\) must be divisible by F\\((.+?)\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/kernels/ops/diffusion/norm/scale_residual_norm_cutedsl.py","lineNumber":229,"sourceCode":"\ndef validate_scale_shift(t: torch.Tensor, B: int, S: int, D: int):\n    if t.dtype not in (torch.float16, torch.bfloat16, torch.float32):\n        raise ValueError(f\"Validate failed: unsupported dtype: {t.dtype}\")\n    failed = False\n    if t.ndim == 1 and (t.shape[0] not in (1, D)):\n        failed = True\n    elif t.ndim == 2 and ((t.shape[0] not in (1, B)) or t.shape[1] != D):\n        failed = True\n    elif t.ndim == 3 and (\n        (t.shape[0] not in (1, B)) or (t.shape[1] not in (1, S) or t.shape[2] != D)\n    ):\n        failed = True\n    elif t.ndim == 4:\n        F = t.shape[1]\n        if t.shape[0] != B or t.shape[2] != 1 or t.shape[3] != D:\n            failed = True\n        elif S % F != 0:\n            raise ValueError(f\"Validate failed: S({S}) must be divisible by F({F}).\")\n    if failed:\n        raise ValueError(f\"Validate failed: unsupported tensor shape: {t.shape}.\")\n    if t.stride()[-1] != 1:\n        raise ValueError(\"Validate failed: not contiguous on dim D.\")\n\n\ndef validate_gate(t: Union[torch.Tensor, int], B: int, S: int, D: int):\n    if not isinstance(t, torch.Tensor):\n        return\n    validate_scale_shift(t, B, S, D)\n\n\n@torch.library.custom_op(\"sglang::fused_norm_scale_shift\", mutates_args=())\ndef fused_norm_scale_shift(\n    x: torch.Tensor,\n    weight: Optional[torch.Tensor],\n    bias: Optional[torch.Tensor],\n    scale: torch.Tensor,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/kernels/ops/diffusion/norm/scale_residual_norm_cutedsl.py#L211-L247","documentation":"When scale/shift is 4D (B, F, 1, D) — per-frame modulation — the sequence length S must be divisible by the number of frames F, because each frame's modulation is broadcast over S/F tokens. validate_scale_shift enforces S % F == 0.","triggerScenarios":"Passing a 4D scale/shift with t.shape == (B, F, 1, D) where F does not divide the activation sequence length S (e.g. S=100, F=7).","commonSituations":"Video diffusion where img token count doesn't evenly match the number of latent frames after a patchify/tokenization change (e.g. patch size or token merge changed S without updating F).","solutions":["Make S a multiple of F: fix the token count/patchify config so frames map evenly onto tokens","Verify F equals the frame count actually used to build the latent, not a stale value","Reshape modulation to a supported 1D (D or 1) or 2D (1/B, D) form if per-frame modulation isn't needed"],"exampleFix":"# before: S=256 tokens but F=7 frames\nfused_norm_scale_shift(x, w, b, scale_4d, shift_4d, \"rms\")\n# after: fix patchify so tokens_per_frame * F == S, e.g. S=256, F=8\nassert S % F == 0","handlingStrategy":"validation","validationCode":"if scale.ndim == 4:\n    F = scale.shape[1]\n    assert S % F == 0, f\"S={S} not divisible by F={F}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep frame count and per-frame token count consistent through patchify changes","Add an assert where latents are built linking S and F"],"tags":["shape","video-diffusion","modulation","validation"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}