{"record":{"id":"1306804cee0c752c","repo":"sgl-project/sglang","slug":"all-ranges-must-be-within-0-max-seqlen-got","errorCode":null,"errorMessage":"All ranges must be within [0, {max_seqlen}], got {range_values}","messagePattern":"All ranges must be within \\[0, (.+?)\\], got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/layers/attention/layer.py","lineNumber":218,"sourceCode":"    device: torch.device,\n) -> dict:\n    \"\"\"Build varlen FA metadata from host-side valid token ranges.\n\n    ``valid_ranges[i]`` contains half-open intervals in row-local coordinates.\n    The intervals are packed in the provided order, matching the flattened\n    ``nonzero`` order for ordinary left-to-right masks.\n    \"\"\"\n\n    range_values = [\n        [(int(start), int(end)) for start, end in row_ranges]\n        for row_ranges in valid_ranges\n    ]\n    if any(\n        start < 0 or end < start or end > max_seqlen\n        for row_ranges in range_values\n        for start, end in row_ranges\n    ):\n        raise ValueError(\n            f\"All ranges must be within [0, {max_seqlen}], got {range_values}\"\n        )\n\n    bs = len(range_values)\n    length_values = [\n        sum(end - start for start, end in row_ranges) for row_ranges in range_values\n    ]\n    valid_lens = torch.as_tensor(length_values, dtype=torch.int32, device=device)\n    cu_seqlens = torch.zeros(bs + 1, dtype=torch.int32, device=device)\n    cu_seqlens[1:] = torch.cumsum(valid_lens, dim=0)\n\n    index_parts = [\n        torch.arange(\n            row * max_seqlen + start,\n            row * max_seqlen + end,\n            dtype=torch.long,\n            device=device,\n        )","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/layers/attention/layer.py#L200-L236","documentation":"This error is raised by build_varlen_mask_meta_from_ranges when building varlen attention mask metadata from per-row (start, end) range pairs. Every range must satisfy 0 <= start <= end <= max_seqlen for every row in range_values; otherwise the varlen layout would be invalid and kernels would read out of bounds or produce garbage.","triggerScenarios":"Calling build_varlen_mask_meta_from_ranges (directly or via build_varlen_mask_meta_from_lengths, the attention layer's forward, or _get_joint_attn_mask_and_meta) with range_values where some start < 0, end < start, or end > max_seqlen. Typically happens when token position offsets for an image/video segment exceed the actual sequence length, or when cumulative prefix lengths are miscomputed.","commonSituations":"Mixture-of-text-and-image batching where the prefix text length plus image token length exceeds max_seqlen; off-by-one in cumulative sum of seq lens; passing ranges indexed against a different (local vs global) sequence length under sequence parallelism; negative start after slicing with a bad offset.","solutions":["Recompute the ranges: verify each row's ranges are sorted, non-overlapping, and that sum(end-start) equals the row's actual token count","Check that max_seqlen passed in matches the padded/total sequence length the ranges were computed against (especially under SP, use the global length, not the shard-local one)","Debug-print range_values and max_seqlen right before the call to find the offending row: [ (s,e) for row in range_values for s,e in row if s<0 or e<s or e>max_seqlen ]","If ranges come from a previous stage, fix the cumulative offset computation upstream (e.g. text prefix length + image segment offsets)"],"exampleFix":"// before\nmeta = build_varlen_mask_meta_from_ranges(ranges, max_seqlen=local_max)\n// after\nassert all(0 <= s <= e <= max_seqlen for row in ranges for s, e in row), f\"bad ranges {ranges} vs max {max_seqlen}\"\nmeta = build_varlen_mask_meta_from_ranges(ranges, max_seqlen=max_seqlen)","handlingStrategy":"validation","validationCode":"def ranges_ok(range_values, max_seqlen):\n    return all(0 <= s <= e <= max_seqlen for row in range_values for s, e in row)\n\nif not ranges_ok(ranges, max_seqlen):\n    bad = [(s, e) for row in ranges for s, e in row if s < 0 or e < s or e > max_seqlen]\n    raise ValueError(f\"invalid ranges {bad} for max_seqlen={max_seqlen}\")","typeGuard":"def is_valid_ranges(rv: list[list[tuple[int, int]]], m: int) -> bool:\n    return all(isinstance(s, int) and isinstance(e, int) and 0 <= s <= e <= m\n               for row in rv for s, e in row)","tryCatchPattern":null,"preventionTips":["Always derive ranges from the same cumulative-length array used to compute max_seqlen","Assert range invariants in test fixtures (see test_prefix_text_plus_full_image_matches_nonzero_builder)","Under sequence parallelism, validate against the global sequence length, not the shard-local one"],"tags":["attention","varlen","mask-metadata","range-validation","multimodal"],"backgroundTag":"input-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}