# Buggy code
def replacement_for_connection(self, connection, is_data=True):
    output_step_id = connection.output_step.id
    if output_step_id not in self.outputs:
        template = "No outputs found for step id %s, outputs are %s"
        message = template % (output_step_id, self.outputs)
        raise Exception(message)
    step_outputs = self.outputs[output_step_id]
    if step_outputs is STEP_OUTPUT_DELAYED:
        delayed_why = (
            "dependent step [%s] delayed, so this step must be delayed" % output_step_id
        )
        raise modules.DelayedWorkflowEvaluation(why=delayed_why)
    output_name = connection.output_name
    try:
        replacement = step_outputs[output_name]
    except KeyError:
        replacement = self.inputs_by_step_id.get(output_step_id)
        if (
            connection.output_step.type == "parameter_input"
            and output_step_id is not None
        ):
            # FIXME: parameter_input step outputs should be properly recorded as step outputs, but for now we can
            # short-circuit and just pick the input value
            pass
        else:
            # Must resolve.
            template = "Workflow evaluation problem - failed to find output_name %s in step_outputs %s"
            message = template % (output_name, step_outputs)
            raise Exception(message)
    if isinstance(replacement, model.HistoryDatasetCollectionAssociation):
        if not replacement.collection.populated:
            if not replacement.collection.waiting_for_elements:
                # If we are not waiting for elements, there was some
                # problem creating the collection. Collection will never
                # be populated.
                # TODO: consider distinguish between cancelled and failed?
                raise modules.CancelWorkflowEvaluation()

            delayed_why = (
                "dependent collection [%s] not yet populated with datasets"
                % replacement.id
            )
            raise modules.DelayedWorkflowEvaluation(why=delayed_why)

    data_inputs = (
        model.HistoryDatasetAssociation,
        model.HistoryDatasetCollectionAssociation,
        model.DatasetCollection,
    )
    if not is_data and isinstance(replacement, data_inputs):
        if isinstance(replacement, model.HistoryDatasetAssociation):
            if replacement.is_pending:
                raise modules.DelayedWorkflowEvaluation()
            if not replacement.is_ok:
                raise modules.CancelWorkflowEvaluation()
        else:
            if not replacement.collection.populated:
                raise modules.DelayedWorkflowEvaluation()
            pending = False
            for dataset_instance in replacement.dataset_instances:
                if dataset_instance.is_pending:
                    pending = True
                elif not dataset_instance.is_ok:
                    raise modules.CancelWorkflowEvaluation()
            if pending:
                raise modules.DelayedWorkflowEvaluation()

    return replacement


# Traceback (Exception)
[pid: 63775|app: 0|req: 160/596] 127.0.0.1 () {50 vars in 1324 bytes} [Wed Jul 31 09:38:45 2019] GET /api/histories/1cd8e2f6b131e891/contents?details=3f5830403180d620&amp;order=hid&amp;v=dev&amp;q=update_time-ge&amp;q=deleted&amp;q=purged&amp;qv=2019-07-31T16%3A38%3A41.000Z&amp;qv=False&amp;qv=False => generated 2 bytes in 53 msecs (HTTP/1.1 200) 3 headers in 139 bytes (1 switches on core 3)
galaxy.workflow.scheduling_manager DEBUG 2019-07-31 09:38:45,835 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Attempting to schedule workflow invocation [(4,)]
galaxy.workflow.run DEBUG 2019-07-31 09:38:45,941 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 10 outputs of invocation 4 delayed (tool [__BUILD_LIST__] inputs are not ready, this special tool requires inputs to be ready)
galaxy.workflow.run DEBUG 2019-07-31 09:38:45,941 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 11 outputs of invocation 4 delayed (dependent step [10] delayed, so this step must be delayed)
galaxy.workflow.run DEBUG 2019-07-31 09:38:45,941 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 12 outputs of invocation 4 delayed (dependent step [11] delayed, so this step must be delayed)
galaxy.workflow.run DEBUG 2019-07-31 09:38:45,942 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 13 outputs of invocation 4 delayed (dependent step [11] delayed, so this step must be delayed)
galaxy.workflow.run DEBUG 2019-07-31 09:38:45,942 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 14 outputs of invocation 4 delayed (dependent step [13] delayed, so this step must be delayed)
galaxy.workflow.scheduling_manager DEBUG 2019-07-31 09:38:45,957 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Workflow invocation [4] scheduled
galaxy.workflow.scheduling_manager DEBUG 2019-07-31 09:38:46,960 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Attempting to schedule workflow invocation [(4,)]
galaxy.workflow.run DEBUG 2019-07-31 09:38:47,070 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 10 outputs of invocation 4 delayed (tool [__BUILD_LIST__] inputs are not ready, this special tool requires inputs to be ready)
galaxy.workflow.run DEBUG 2019-07-31 09:38:47,071 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 11 outputs of invocation 4 delayed (dependent step [10] delayed, so this step must be delayed)
galaxy.workflow.run DEBUG 2019-07-31 09:38:47,071 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 12 outputs of invocation 4 delayed (dependent step [11] delayed, so this step must be delayed)
galaxy.workflow.run DEBUG 2019-07-31 09:38:47,072 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 13 outputs of invocation 4 delayed (dependent step [11] delayed, so this step must be delayed)
galaxy.workflow.run DEBUG 2019-07-31 09:38:47,072 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Marking step 14 outputs of invocation 4 delayed (dependent step [13] delayed, so this step must be delayed)
galaxy.workflow.scheduling_manager DEBUG 2019-07-31 09:38:47,086 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Workflow invocation [4] scheduled
galaxy.jobs.runners.drmaa DEBUG 2019-07-31 09:38:47,465 [p:63775,w:2,m:0] [SlurmRunner.monitor_thread] (10/24674328) state change: job finished normally
galaxy.model.metadata DEBUG 2019-07-31 09:38:47,587 [p:63775,w:2,m:0] [SlurmRunner.work_thread-0] loading metadata from file for: HistoryDatasetAssociation 16
galaxy.jobs INFO 2019-07-31 09:38:47,692 [p:63775,w:2,m:0] [SlurmRunner.work_thread-0] Collecting metrics for Job 10 in /project/6004808/ncm3/galaxy-19.05-git/galaxy-database/jobs_directory/000/10
galaxy.jobs DEBUG 2019-07-31 09:38:47,703 [p:63775,w:2,m:0] [SlurmRunner.work_thread-0] job 10 ended (finish() executed in (159.904 ms))
galaxy.workflow.scheduling_manager DEBUG 2019-07-31 09:38:48,090 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Attempting to schedule workflow invocation [(4,)]
galaxy.managers.collections DEBUG 2019-07-31 09:38:48,247 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Created collection with 2 elements
/project/6004808/ncm3/galaxy-19.05-git/galaxy/.venv/lib/python2.7/site-packages/sqlalchemy/sql/sqltypes.py:268: SAWarning: Unicode type received non-unicode bind param value 'list'. (this warning may be suppressed after 10 occurrences)
(util.ellipses_string(value),),
/project/6004808/ncm3/galaxy-19.05-git/galaxy/.venv/lib/python2.7/site-packages/sqlalchemy/sql/sqltypes.py:268: SAWarning: Unicode type received non-unicode bind param value 'output'. (this warning may be suppressed after 10 occurrences)
(util.ellipses_string(value),),
galaxy.tools.actions.model_operations INFO 2019-07-31 09:38:48,343 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Calling produce_outputs, tool is <galaxy.tools.BuildListCollectionTool object at 0x7f32a9f2a690>
galaxy.tools.execute DEBUG 2019-07-31 09:38:48,348 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Tool [__BUILD_LIST__] created job [11] (153.141 ms)
galaxy.tools.execute DEBUG 2019-07-31 09:38:48,358 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Executed 1 job(s) for tool __BUILD_LIST__ request: (178.532 ms)
galaxy.workflow.run DEBUG 2019-07-31 09:38:48,368 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Workflow step 10 of invocation 4 invoked (189.270 ms)
galaxy.managers.collections DEBUG 2019-07-31 09:38:48,441 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Created collection with 0 elements
galaxy.managers.collections DEBUG 2019-07-31 09:38:48,469 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Created collection with 2 elements
/project/6004808/ncm3/galaxy-19.05-git/galaxy/.venv/lib/python2.7/site-packages/sqlalchemy/sql/sqltypes.py:268: SAWarning: Unicode type received non-unicode bind param value 'input'. (this warning may be suppressed after 10 occurrences)
(util.ellipses_string(value),),
/project/6004808/ncm3/galaxy-19.05-git/galaxy/.venv/lib/python2.7/site-packages/sqlalchemy/sql/sqltypes.py:268: SAWarning: Unicode type received non-unicode bind param value 'output_discarded'. (this warning may be suppressed after 10 occurrences)
(util.ellipses_string(value),),
galaxy.tools.actions.model_operations INFO 2019-07-31 09:38:48,512 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Calling produce_outputs, tool is <galaxy.tools.FilterFromFileTool object at 0x7f32a9f63810>
galaxy.tools.execute DEBUG 2019-07-31 09:38:48,516 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Tool [__FILTER_FROM_FILE__] created job [12] (106.710 ms)
galaxy.tools.execute DEBUG 2019-07-31 09:38:48,524 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Executed 1 job(s) for tool __FILTER_FROM_FILE__ request: (140.242 ms)
galaxy.workflow.run DEBUG 2019-07-31 09:38:48,533 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Workflow step 11 of invocation 4 invoked (164.122 ms)
galaxy.workflow.run ERROR 2019-07-31 09:38:48,553 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Failed to schedule Workflow[id=2,name=test merge empty (imported from uploaded file)], problem occurred on WorkflowStep[index=4,type=tool].
Traceback (most recent call last):
File "lib/galaxy/workflow/run.py", line 190, in invoke
incomplete_or_none = self._invoke_step(workflow_invocation_step)
File "lib/galaxy/workflow/run.py", line 266, in _invoke_step
use_cached_job=self.workflow_invocation.use_cached_job)
File "lib/galaxy/workflow/modules.py", line 1189, in execute
collection_info = self.compute_collection_info(progress, step, all_inputs)
File "lib/galaxy/workflow/modules.py", line 309, in compute_collection_info
progress, step, all_inputs
File "lib/galaxy/workflow/modules.py", line 327, in _find_collections_to_match
data = progress.replacement_for_input(step, input_dict)
File "lib/galaxy/workflow/run.py", line 337, in replacement_for_input
replacement = self.replacement_for_connection(connection[0], is_data=is_data)
File "lib/galaxy/workflow/run.py", line 358, in replacement_for_connection
raise Exception(message)
Exception: Workflow evaluation problem - failed to find output_name output in step_outputs {}
galaxy.workflow.run ERROR 2019-07-31 09:38:48,697 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Failed to execute scheduled workflow.
Traceback (most recent call last):
File "lib/galaxy/workflow/run.py", line 83, in __invoke
outputs = invoker.invoke()
File "lib/galaxy/workflow/run.py", line 190, in invoke
incomplete_or_none = self._invoke_step(workflow_invocation_step)
File "lib/galaxy/workflow/run.py", line 266, in _invoke_step
use_cached_job=self.workflow_invocation.use_cached_job)
File "lib/galaxy/workflow/modules.py", line 1189, in execute
collection_info = self.compute_collection_info(progress, step, all_inputs)
File "lib/galaxy/workflow/modules.py", line 309, in compute_collection_info
progress, step, all_inputs
File "lib/galaxy/workflow/modules.py", line 327, in _find_collections_to_match
data = progress.replacement_for_input(step, input_dict)
File "lib/galaxy/workflow/run.py", line 337, in replacement_for_input
replacement = self.replacement_for_connection(connection[0], is_data=is_data)
File "lib/galaxy/workflow/run.py", line 358, in replacement_for_connection
raise Exception(message)
Exception: Workflow evaluation problem - failed to find output_name output in step_outputs {}
galaxy.workflow.scheduling_manager DEBUG 2019-07-31 09:38:48,712 [p:63775,w:2,m:0] [WorkflowRequestMonitor.monitor_thread] Workflow invocation [4] scheduled

# Fixed code
def replacement_for_connection(self, connection, is_data=True):
    output_step_id = connection.output_step.id
    if output_step_id not in self.outputs:
        template = "No outputs found for step id %s, outputs are %s"
        message = template % (output_step_id, self.outputs)
        raise Exception(message)
    step_outputs = self.outputs[output_step_id]
    if step_outputs is STEP_OUTPUT_DELAYED:
        delayed_why = (
            "dependent step [%s] delayed, so this step must be delayed" % output_step_id
        )
        raise modules.DelayedWorkflowEvaluation(why=delayed_why)
    output_name = connection.output_name
    try:
        replacement = step_outputs[output_name]
    except KeyError:
        # Must resolve.
        template = "Workflow evaluation problem - failed to find output_name %s in step_outputs %s"
        message = template % (output_name, step_outputs)
        raise Exception(message)
    if isinstance(replacement, model.HistoryDatasetCollectionAssociation):
        if not replacement.collection.populated:
            if not replacement.collection.waiting_for_elements:
                # If we are not waiting for elements, there was some
                # problem creating the collection. Collection will never
                # be populated.
                # TODO: consider distinguish between cancelled and failed?
                raise modules.CancelWorkflowEvaluation()

            delayed_why = (
                "dependent collection [%s] not yet populated with datasets"
                % replacement.id
            )
            raise modules.DelayedWorkflowEvaluation(why=delayed_why)

    data_inputs = (
        model.HistoryDatasetAssociation,
        model.HistoryDatasetCollectionAssociation,
        model.DatasetCollection,
    )
    if not is_data and isinstance(replacement, data_inputs):
        if isinstance(replacement, model.HistoryDatasetAssociation):
            if replacement.is_pending:
                raise modules.DelayedWorkflowEvaluation()
            if not replacement.is_ok:
                raise modules.CancelWorkflowEvaluation()
        else:
            if not replacement.collection.populated:
                raise modules.DelayedWorkflowEvaluation()
            pending = False
            for dataset_instance in replacement.dataset_instances:
                if dataset_instance.is_pending:
                    pending = True
                elif not dataset_instance.is_ok:
                    raise modules.CancelWorkflowEvaluation()
            if pending:
                raise modules.DelayedWorkflowEvaluation()

    return replacement