# Buggy code
def cleanup(prefix, inputs, values):
    for key, input in inputs.items():
        if isinstance(input, DataToolParameter) or isinstance(
            input, DataCollectionToolParameter
        ):
            tmp = values[key]
            values[key] = None
            # HACK: Nested associations are not yet working, but we
            #       still need to clean them up so we can serialize
            # if not( prefix ):
            if isinstance(tmp, model.DatasetCollectionElement):
                tmp = tmp.first_dataset_instance()
            if tmp:  # this is false for a non-set optional dataset
                if not isinstance(tmp, list):
                    associations.append((tmp.hid, prefix + key))
                else:
                    associations.extend([(t.hid, prefix + key) for t in tmp])

            # Cleanup the other deprecated crap associated with datasets
            # as well. Worse, for nested datasets all the metadata is
            # being pushed into the root. FIXME: MUST REMOVE SOON
            key = prefix + key + "_"
            for k in root_values.keys():
                if k not in root_input_keys and k.startswith(key):
                    del root_values[k]
        elif isinstance(input, Repeat):
            if key in values:
                group_values = values[key]
                for i, rep_values in enumerate(group_values):
                    rep_index = rep_values["__index__"]
                    cleanup(
                        "%s%s_%d|" % (prefix, key, rep_index),
                        input.inputs,
                        group_values[i],
                    )
        elif isinstance(input, Conditional):
            # Scrub dynamic resource related parameters from workflows,
            # they cause problems and the workflow probably should include
            # their state in workflow encoding.
            if input.name == "__job_resource":
                if input.name in values:
                    del values[input.name]
                return
            if input.name in values:
                group_values = values[input.name]
                current_case = group_values["__current_case__"]
                cleanup(
                    "%s%s|" % (prefix, key),
                    input.cases[current_case].inputs,
                    group_values,
                )
        elif isinstance(input, Section):
            if input.name in values:
                cleanup("%s%s|" % (prefix, key), input.inputs, values[input.name])


# Traceback (AttributeError)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: 80.138.30.147 - - [18/Oct/2020:23:43:09 +0200] "POST /workflow/build_from_current_history HTTP/1.1" 500 - "https://usegalaxy.eu/workflow/build_from_current_history" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0"
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: Traceback (most recent call last):
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/web/framework/middleware/error.py", line 154, in __call__
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: app_iter = self.application(environ, sr_checker)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "/opt/galaxy/venv/lib64/python3.6/site-packages/paste/recursive.py", line 85, in __call__
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: return self.application(environ, start_response)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/web/framework/middleware/statsd.py", line 34, in __call__
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: req = self.application(environ, start_response)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "/opt/galaxy/venv/lib64/python3.6/site-packages/paste/httpexceptions.py", line 640, in __call__
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: return self.application(environ, start_response)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/web/framework/base.py", line 145, in __call__
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: return self.handle_request(environ, start_response)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/web/framework/base.py", line 224, in handle_request
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: body = method(trans, **kwargs)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/webapps/galaxy/controllers/workflow.py", line 854, in build_from_current_history
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: dataset_collection_names=dataset_collection_names
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 29, in extract_workflow
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: steps = extract_steps(trans, history=history, job_ids=job_ids, dataset_ids=dataset_ids, dataset_collection_ids=dataset_collection_ids, dataset_names=dataset_names, dataset_collection_names=None)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 109, in extract_steps
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: tool_inputs, associations = step_inputs(trans, job)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 310, in step_inputs
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: associations = __cleanup_param_values(tool.inputs, param_values)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 372, in __cleanup_param_values
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: cleanup("", inputs, values)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 368, in cleanup
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: cleanup("%s%s|" % (prefix, key), input.cases[current_case].inputs, group_values)
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 342, in cleanup
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: associations.extend([(t.hid, prefix + key) for t in tmp])
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: File "lib/galaxy/workflow/extract.py", line 342, in <listcomp>
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: associations.extend([(t.hid, prefix + key) for t in tmp])
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: AttributeError: 'DatasetCollectionElement' object has no attribute 'hid'
Oct 18 23:43:10 sn04.bi.uni-freiburg.de uwsgi[1008399]: The above exception was the direct cause of the

# Fixed code
def cleanup(prefix, inputs, values):
    for key, input in inputs.items():
        if isinstance(input, DataToolParameter) or isinstance(
            input, DataCollectionToolParameter
        ):
            items = values[key]
            values[key] = None
            # HACK: Nested associations are not yet working, but we
            #       still need to clean them up so we can serialize
            # if not( prefix ):
            for item in listify(items):
                if isinstance(item, model.DatasetCollectionElement):
                    item = item.first_dataset_instance()
                if item:  # this is false for a non-set optional dataset
                    associations.append((item.hid, prefix + key))

            # Cleanup the other deprecated crap associated with datasets
            # as well. Worse, for nested datasets all the metadata is
            # being pushed into the root. FIXME: MUST REMOVE SOON
            key = prefix + key + "_"
            for k in root_values.keys():
                if k not in root_input_keys and k.startswith(key):
                    del root_values[k]
        elif isinstance(input, Repeat):
            if key in values:
                group_values = values[key]
                for i, rep_values in enumerate(group_values):
                    rep_index = rep_values["__index__"]
                    cleanup(
                        "%s%s_%d|" % (prefix, key, rep_index),
                        input.inputs,
                        group_values[i],
                    )
        elif isinstance(input, Conditional):
            # Scrub dynamic resource related parameters from workflows,
            # they cause problems and the workflow probably should include
            # their state in workflow encoding.
            if input.name == "__job_resource":
                if input.name in values:
                    del values[input.name]
                return
            if input.name in values:
                group_values = values[input.name]
                current_case = group_values["__current_case__"]
                cleanup(
                    "%s%s|" % (prefix, key),
                    input.cases[current_case].inputs,
                    group_values,
                )
        elif isinstance(input, Section):
            if input.name in values:
                cleanup("%s%s|" % (prefix, key), input.inputs, values[input.name])