{"record":{"id":"66a2b1726a59be10","repo":"sgl-project/sglang","slug":"invalid-duration-in-action-segment-segment-r","errorCode":null,"errorMessage":"invalid duration in action segment {segment!r}","messagePattern":"invalid duration in action segment (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/sana_wm/base.py","lineNumber":133,"sourceCode":"            raise ValueError(f\"{error_label} must be list[list[str]]\")\n        out.append([str(key).lower() for key in frame_actions])\n    return out\n\n\ndef parse_sana_wm_action_string(action: str) -> list[list[str]]:\n    cleaned = \"\".join(action.replace(\"，\", \",\").split())\n    if not cleaned:\n        raise ValueError(\"action string is empty\")\n\n    per_frame: list[list[str]] = []\n    for segment in cleaned.split(\",\"):\n        if not segment or \"-\" not in segment:\n            raise ValueError(\n                f\"invalid action segment {segment!r}; expected '<keys>-<frames>'\"\n            )\n        keys_part, duration = segment.rsplit(\"-\", 1)\n        if not duration.isdigit() or int(duration) <= 0:\n            raise ValueError(f\"invalid duration in action segment {segment!r}\")\n\n        if keys_part.lower() == \"none\":\n            keys: list[str] = []\n        else:\n            bad = sorted(\n                {\n                    char\n                    for char in keys_part.lower()\n                    if char not in _SANA_WM_ALLOWED_ACTION_KEYS\n                }\n            )\n            if bad:\n                raise ValueError(\n                    f\"unknown action keys {bad}; allowed keys are \"\n                    f\"{sorted(_SANA_WM_ALLOWED_ACTION_KEYS)}\"\n                )\n            keys = sorted(set(keys_part.lower()))\n        # Fresh list per frame: repeated frames must NOT alias one list object","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/sana_wm/base.py#L115-L151","documentation":"Raised by parse_sana_wm_action_string when the frames part of a segment (after the last '-') is not all digits or is <= 0. Duration must be a positive integer.","triggerScenarios":"Segments like 'ab-0', 'ab--1', 'ab-4.5', 'ab-x', or 'ab-' (empty duration). The code does segment.rsplit('-',1) then checks duration.isdigit() and int(duration) > 0.","commonSituations":"Zero or negative frame counts from user input; float durations like '4.5'; negative numbers creating '--1' after rsplit.","solutions":["Use a positive integer duration: 'ab-4' not 'ab-0' or 'ab-4.5'","Clamp/round durations upstream: f'{max(1, round(d))}'","Reject the request early with a clear message if duration parses to < 1"],"exampleFix":"// before\nsegment = 'ab-0'\n// after\nsegment = 'ab-1'","handlingStrategy":"validation","validationCode":"assert all(p.isdigit() and int(p) > 0 for p in (seg.rsplit('-',1)[1] for seg in segments))","typeGuard":"def durations_valid(s: str) -> bool:\n    return all((lambda d: d.isdigit() and int(d) > 0)(seg.rsplit('-',1)[-1]) for seg in s.split(',') if seg)","tryCatchPattern":null,"preventionTips":["Clamp parsed durations to >= 1 at the input boundary","Reject float/zero durations in request validation"],"tags":["validation","action-string","duration","sana-wm"],"backgroundTag":"invalid-numeric-range","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}