Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions lib/galaxy/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
swap_inf_nan,
)
from galaxy.util.path import StrPath
from galaxy.util.permutations import InputMatchedException
from galaxy.util.rules_dsl import RuleSet
from galaxy.util.template import (
fill_template,
Expand Down Expand Up @@ -2109,6 +2110,15 @@ def visit_inputs(self, values, callback):
if self.check_values:
visit_input_values(self.inputs, values, callback)

def _raise_matched_input_errors(self, exc: InputMatchedException) -> None:
"""Convert matched-input expansion errors to validation errors.

When multi-input parameters have mismatched lengths, this surfaces
the error as a request validation error (400) instead of a generic
server error.
"""
raise exceptions.RequestParameterInvalidException(str(exc)) from exc

def expand_incoming_async(
self,
request_context: WorkRequestContext,
Expand All @@ -2135,9 +2145,12 @@ def expand_incoming_async(
expanded_incomings: list[ToolStateJobInstanceExpansionT]
job_tool_states: list[ToolStateJobInstanceT]
collection_info: MatchingCollections | None
expanded_incomings, job_tool_states, collection_info = expand_meta_parameters_async(
request_context.app, self, tool_request_internal_state
)
try:
expanded_incomings, job_tool_states, collection_info = expand_meta_parameters_async(
request_context.app, self, tool_request_internal_state
)
except InputMatchedException as exc:
self._raise_matched_input_errors(exc)

self._ensure_expansion_is_valid(job_tool_states, rerun_remap_job_id)

Expand Down Expand Up @@ -2184,9 +2197,12 @@ def expand_incoming(
# Expand these out to individual parameters for given jobs (tool executions).
expanded_incomings: list[ToolStateJobInstanceExpansionT]
collection_info: MatchingCollections | None
expanded_incomings, collection_info = expand_meta_parameters(
request_context, self, incoming, input_format=input_format
)
try:
expanded_incomings, collection_info = expand_meta_parameters(
request_context, self, incoming, input_format=input_format
)
except InputMatchedException as exc:
self._raise_matched_input_errors(exc)

self._ensure_expansion_is_valid(expanded_incomings, rerun_remap_job_id)

Expand Down
36 changes: 36 additions & 0 deletions lib/galaxy_test/api/test_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,42 @@ def test_job_build_for_rerun_hdca_value_in_options(self, history_id):
hdca_option = f1_input["options"]["hdca"][0]
assert hdca_option["id"] == hdca_id and hdca_option["src"] == "hdca"

@requires_new_history
@skip_without_tool("multi_data_param")
def test_async_job_submission_rejects_mismatched_multi_inputs(self, history_id):
"""API-level regression test for async /api/jobs submission.

Mismatched lengths for matched multi-input parameters should be
surfaced as a request validation error (400) instead of a generic
server error.
"""
dataset_id_1 = self.__history_with_ok_dataset(history_id)
dataset_id_2 = self.__history_with_ok_dataset(history_id)

inputs = {
"f1": {
"batch": True,
"values": [
{"src": "hda", "id": dataset_id_1},
{"src": "hda", "id": dataset_id_2},
],
},
"f2": {
"batch": True,
"values": [
{"src": "hda", "id": dataset_id_1},
],
},
}

response = self.dataset_populator.tool_request_raw(
tool_id="multi_data_param",
inputs=inputs,
history_id=history_id,
)
self._assert_status_code_is(response, 400)
assert "should be of equal length" in response.json()["err_msg"]

@skip_without_tool("multiple_versions")
def test_job_build_for_rerun_switch_version(self, history_id):
run_response = self._run("multiple_versions", history_id, {}, tool_version="0.1").json()
Expand Down
Loading