diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 05cbb2c6b8d..ef01c27f7f6 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -1117,6 +1117,17 @@ class SelectToolParameter(ToolParameter): ) if is_runtime_value(value): return None + if isinstance(value, dict): + # A dict is unhashable and can never be a legal value, but + # testing membership against the set of legal values would + # raise an opaque "unhashable type" TypeError. Treat it as an + # invalid option instead. + raise ParameterValueError( + f"an invalid option ({value!r}) was selected (valid options: {','.join(iter_to_string(legal_values))})", + self.name, + value, + is_dynamic=self.is_dynamic, + ) if value in legal_values: return value elif value in fallback_values: diff --git a/test/unit/app/tools/test_select_parameters.py b/test/unit/app/tools/test_select_parameters.py index 6c9fcaa38f1..b24ba677211 100644 --- a/test/unit/app/tools/test_select_parameters.py +++ b/test/unit/app/tools/test_select_parameters.py @@ -26,6 +26,14 @@ class TestSelectToolParameter(BaseParameterTestCase): self.param.from_json("42", self.trans) assert str(exc_info.value) == "Parameter 'my_name': requires a value, but no legal values defined" + def test_dict_value_is_invalid_option(self): + # A dict value is unhashable; checking it against the set of legal + # values used to raise an opaque "unhashable type: 'dict'" TypeError. + param = self._parameter_for(xml="""""") + with pytest.raises(ValueError) as exc_info: + param.from_json({"not": "valid"}, self.trans) + assert "an invalid option" in str(exc_info.value) + def test_unvalidated_values(self): self.options_xml = """""" self.trans.workflow_building_mode = True