diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 91d07badae1..3c70f0800da 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2215,6 +2215,12 @@ class DataToolParameter(BaseDataToolParameter): ), ): rval.append(single_value) + elif single_value in (None, "None", ""): + # An unset optional data input (e.g. connected to a multiple + # data parameter) arrives as a null list element. Tolerate it + # as "no dataset" the way to_python() filters it, rather than + # treating null as a malformed id (regression from #22617). + continue else: pk = _decode_dataset_id(single_value, trans.security, self.name) rval.append(trans.sa_session.get(HistoryDatasetAssociation, pk)) diff --git a/test/unit/app/tools/test_data_parameters.py b/test/unit/app/tools/test_data_parameters.py index 3acf51d77e5..9beefa850d4 100644 --- a/test/unit/app/tools/test_data_parameters.py +++ b/test/unit/app/tools/test_data_parameters.py @@ -45,6 +45,16 @@ class TestDataToolParameter(BaseParameterTestCase): with pytest.raises(ParameterValueError, match="invalid dataset id"): self.param.from_json("not-an-id", self.trans) + def test_from_json_multi_tolerates_none(self): + # An unset optional data input connected to a multiple data parameter + # arrives as a null list element; it must be filtered out rather than + # rejected as a malformed id (regression from #22617, surfaced as a + # workflow run erroring on an unset optional data input). + self.multiple = True + self.optional = True + assert self.param.from_json([None], self.trans) == [] + assert self.param.from_json(["None"], self.trans) == [] + def test_field_filter_on_types(self): hda1 = MockHistoryDatasetAssociation(name="hda1", id=1) hda2 = MockHistoryDatasetAssociation(name="hda2", id=2)