{"record":{"id":"e5a54e3521bfa9e3","repo":"sgl-project/sglang","slug":"cosmos3-action-horizon-must-be-divisible-by-4-so-n","errorCode":null,"errorMessage":"Cosmos3 action_horizon must be divisible by 4 so num_frames is compatible with the temporal VAE","messagePattern":"Cosmos3 action_horizon must be divisible by 4 so num_frames is compatible with the temporal VAE","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/entrypoints/action/cosmos3.py","lineNumber":166,"sourceCode":"    if action_horizon is None and num_frames is None:\n        action_horizon = 16\n    if action_horizon is not None:\n        action_horizon = int(action_horizon)\n        if action_horizon <= 0:\n            raise ValueError(\"action_horizon must be a positive integer\")\n        expected_num_frames = action_horizon + 1\n        if num_frames is not None and int(num_frames) != expected_num_frames:\n            raise ValueError(\n                \"Cosmos3 requires num_frames == action_horizon + 1, got \"\n                f\"num_frames={num_frames}, action_horizon={action_horizon}\"\n            )\n        num_frames = expected_num_frames\n    else:\n        num_frames = int(num_frames)\n        if num_frames <= 1:\n            raise ValueError(\"Cosmos3 action num_frames must be greater than 1\")\n    if (num_frames - 1) % 4 != 0:\n        raise ValueError(\n            \"Cosmos3 action_horizon must be divisible by 4 so num_frames \"\n            \"is compatible with the temporal VAE\"\n        )\n\n    images = _images_from_observation(observation)\n    video_path = options.get(\"video_path\") or observation.get(\"video\")\n    if action_mode == \"policy\" and not images:\n        raise ValueError(\"Cosmos3 policy input requires an observation image\")\n    if action_mode == \"inverse_dynamics\" and video_path is None:\n        raise ValueError(\"Cosmos3 inverse_dynamics input requires an observation video\")\n    if images and video_path is not None:\n        raise ValueError(\"Cosmos3 action requests accept either an image or a video\")\n    batch_size = len(images) if images else 1\n    max_batch_size = max(1, int(getattr(server_args, \"batching_max_size\", 1)))\n    if batch_size > max_batch_size:\n        raise ValueError(\n            f\"Cosmos3 action batch size {batch_size} exceeds \"\n            f\"--batching-max-size={max_batch_size}\"","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/entrypoints/action/cosmos3.py#L148-L184","documentation":"Cosmos3's temporal VAE downsamples time by 4, so the action horizon (num_frames - 1) must be divisible by 4. After resolving num_frames (from action_horizon or directly), the endpoint checks (num_frames - 1) % 4 == 0 and rejects otherwise. Valid num_frames are 5, 9, 13, 17, ... (horizons 4, 8, 12, 16, ...).","triggerScenarios":"action_horizon=10 (num_frames=11); num_frames=20 — any value where (num_frames-1) % 4 != 0.","commonSituations":"Tuning horizon to an arbitrary control-loop length (e.g. 10 Hz robot with 1s chunk); porting configs from models without temporal VAE constraints.","solutions":["Round action_horizon to the nearest multiple of 4 (default 16 → num_frames 17)","If you need a different effective horizon, generate the nearest larger multiple of 4 and slice the returned actions to your desired length"],"exampleFix":"# before\n{\"parameters\": {\"action_horizon\": 10}}\n# after\n{\"parameters\": {\"action_horizon\": 12}}","handlingStrategy":"validation","validationCode":"nf = int(params.get('num_frames', int(params.get('action_horizon', 16)) + 1))\nassert (nf - 1) % 4 == 0, 'action_horizon must be divisible by 4'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Snap horizons to multiples of 4 client-side: h = max(4, round(h/4)*4)","Slice returned action chunks to the exact length your controller needs"],"tags":["cosmos3","temporal-vae","divisibility","action-horizon"],"backgroundTag":"shape-divisibility-constraint","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}