[Bugfix][Structured Output] Disallow MRV1 + PP>1 + async sched + structured output (#56250)
Signed-off-by: Artem Perevedentsev <aperevedents@nvidia.com> Co-authored-by: CNE Pierre FICHEPOIL <pierre-1.fichepoil@gendarmerie.interieur.gouv.fr>
Artem Perevedentsev committed
Sep 22, 2026 at 17:00 UTC
1ea7c63f4af7bb4fd6f025c8db44434ab274cb51
2 files changed
+67
-2
tests/test_config.py
+44
-2
@@ -1082,10 +1082,11 @@ def test_models_default_to_v2_model_runner(model_config, expected, monkeypatch):
1082
1083
def test_v1_model_runner_rejects_v2_only_features():
1084
config = SimpleNamespace(
1085
- parallel_config=SimpleNamespace(
1085
+ parallel_config=ParallelConfig(
1086
prefill_context_parallel_size=2,
1087
- enable_batch_sharded_sampling=False,
1087
+ distributed_executor_backend="mp",
1088
),
1089
+ scheduler_config=SchedulerConfig.default_factory(async_scheduling=False),
1090
speculative_config=None,
1091
model_config=None,
1092
)
@@ -1245,6 +1246,47 @@ def test_async_scheduling_with_pipeline_parallelism_is_allowed():
1246
assert cfg.scheduler_config.async_scheduling is True
1247
1248
1249
+def test_v1_model_runner_drops_async_scheduling_with_pipeline_parallelism(monkeypatch):
1250
+ """PP>1 must stay buildable whenever the V1 model runner is selected, such
1251
+ as the external_launcher fallback; async scheduling is dropped instead."""
1252
+ monkeypatch.setenv("VLLM_USE_V2_MODEL_RUNNER", "0")
1253
+
1254
+ cfg = VllmConfig(
1255
+ scheduler_config=SchedulerConfig(
1256
+ max_model_len=8192,
1257
+ is_encoder_decoder=False,
1258
+ ),
1259
+ parallel_config=ParallelConfig(
1260
+ pipeline_parallel_size=2,
1261
+ distributed_executor_backend="mp",
1262
+ nnodes=2,
1263
+ ),
1264
+ )
1265
+ assert cfg.scheduler_config.async_scheduling is False
1266
+
1267
+
1268
+def test_v1_model_runner_rejects_pipeline_parallelism_with_async_scheduling():
1269
+ """Only the async combination desyncs the grammar FSM (#45014), so plain
1270
+ PP>1 must stay usable on the V1 model runner."""
1271
+ config = SimpleNamespace(
1272
+ parallel_config=ParallelConfig(
1273
+ pipeline_parallel_size=2,
1274
+ distributed_executor_backend="mp",
1275
+ ),
1276
+ scheduler_config=SchedulerConfig.default_factory(async_scheduling=False),
1277
+ speculative_config=None,
1278
+ model_config=None,
1279
+ )
1280
+ config._dflash_needs_multi_kv_group = lambda: False
1281
+ config._is_dflash2_draft = lambda: False
1282
+
1283
+ assert VllmConfig._get_v1_model_runner_unsupported_features(config) == []
1284
+
1285
+ config.scheduler_config.async_scheduling = True
1286
+ unsupported = VllmConfig._get_v1_model_runner_unsupported_features(config)
1287
+ assert "pipeline parallelism with async scheduling" in unsupported
1288
+
1289
+
1290
def test_data_parallel_rpc_port_has_fixed_default():
1291
assert ParallelConfig().data_parallel_rpc_port == 29550
1292
vllm/config/vllm.py
+23
@@ -1522,6 +1522,15 @@ class VllmConfig:
1522
"DP+EP generation accuracy."
1523
)
1524
self.scheduler_config.async_scheduling = False
1525
+ elif (
1526
+ self.parallel_config.pipeline_parallel_size > 1
1527
+ and not self.use_v2_model_runner
1528
+ ):
1529
+ logger.warning_once(
1530
+ "Async scheduling is disabled because the V1 model runner "
1531
+ "does not support it with pipeline parallelism."
1532
+ )
1533
+ self.scheduler_config.async_scheduling = False
1534
else:
1535
self.scheduler_config.async_scheduling = True
1536
@@ -2962,6 +2971,20 @@ class VllmConfig:
2971
if self.parallel_config.prefill_context_parallel_size > 1:
2972
unsupported.append("prefill context parallel")
2973
2974
+ # Note(arpera):
2975
+ # MRV1 + PP>1 + async sched + structured output
2976
+ # does not work in vLLM. For more info see:
2977
+ # https://github.com/vllm-project/vllm/issues/45014
2978
+ # Since recently MRV1 has been deprecated then
2979
+ # there was decided not to fix the issue but instead
2980
+ # to disallow such configuration.
2981
+ # At the same time MRV2 works fine in this case.
2982
+ if (
2983
+ self.parallel_config.pipeline_parallel_size > 1
2984
+ and self.scheduler_config.async_scheduling
2985
+ ):
2986
+ unsupported.append("pipeline parallelism with async scheduling")
2987
+
2988
# DSpark is implemented only by the V2 GPU model runner.
2989
if self.speculative_config:
2990
if self.speculative_config.method == "dspark":