From b3f6dd71a710453efcb37f38ce6114692078e484 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Tue, 7 Apr 2026 14:33:01 +0200 Subject: [PATCH] Reject HDCA submitted to single data parameter A non-multiple ``data`` parameter cannot reduce a dataset collection, but ``DataToolParameter.from_json`` silently accepted an HDCA value. ``collect_input_dataset_collections`` then rewrote the populated state to a list of the collection's HDAs and ``wrap_values`` later crashed with a raw ``TypeError: Expected [...] to be hashable``, surfacing as a noisy 500 instead of a 4xx client error. Reject the HDCA in ``from_json`` with a clear ``ParameterValueError``. Map-over via ``{"batch": true, "values": [...]}`` is unaffected because it is expanded to per-element jobs before reaching ``from_json``. Fixes #22401 --- lib/galaxy/tools/parameters/basic.py | 18 +++++++++++++++++- lib/galaxy_test/api/test_tools.py | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index a60053b711d..65d2a7c8767 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2275,7 +2275,23 @@ class DataToolParameter(BaseDataToolParameter): if len(rval) > 1: raise ParameterValueError("more than one dataset supplied to single input dataset parameter", self.name) if len(rval) > 0: - return rval[0] + single_value = rval[0] + if isinstance(single_value, HistoryDatasetCollectionAssociation): + # A non-multiple data parameter cannot reduce a dataset + # collection. Without this check the HDCA is silently + # accepted here, then ``collect_input_dataset_collections`` + # rewrites the state to a list of the collection's HDAs and + # ``wrap_values`` later crashes with a raw ``TypeError`` + # (https://github.com/galaxyproject/galaxy/issues/22401). + # Map-over remains supported via ``{"batch": true, ...}``, + # which is expanded to per-element jobs before reaching + # ``from_json``. + raise ParameterValueError( + "dataset collection supplied to single input dataset parameter; " + "to run the tool over each element of the collection, use the map-over option", + self.name, + ) + return single_value else: raise ParameterValueError("invalid dataset supplied to single input dataset parameter", self.name) return rval diff --git a/lib/galaxy_test/api/test_tools.py b/lib/galaxy_test/api/test_tools.py index d6cc99fce75..4f5af059483 100644 --- a/lib/galaxy_test/api/test_tools.py +++ b/lib/galaxy_test/api/test_tools.py @@ -2468,6 +2468,22 @@ class TestToolsApi(ApiTestCase, TestsTools): collection.assert_has_dataset_element("forward").with_contents_stripped("forward") collection.assert_has_dataset_element("reverse").with_contents_stripped("reverse") + @skip_without_tool("identifier_in_conditional") + def test_hdca_rejected_for_single_data_param_in_conditional(self, history_id): + # Regression test for https://github.com/galaxyproject/galaxy/issues/22401 . + # Submitting a paired collection (no batch wrapper) to a non-multiple + # ``data`` parameter is invalid and must produce a 400 client error, + # not a 500 from a TypeError raised inside ``wrap_values``. Map-over is + # still supported via ``{"batch": True, "values": [...]}``, exercised + # by ``test_identifier_map_over_input_in_conditional``. + hdca_id = self._build_pair(history_id, ["123", "456"]) + inputs = { + "outer_cond|multi_input": False, + "outer_cond|input1": {"src": "hdca", "id": hdca_id}, + } + response = self._run("identifier_in_conditional", history_id, inputs) + self._assert_status_code_is(response, 400) + @skip_without_tool("identifier_multiple_in_conditional") def test_identifier_multiple_reduce_in_conditional(self, history_id): hdca_id = self._build_pair(history_id, ["123", "456"])