# Buggy code
def process_train_step_outputs(
    self, all_train_step_outputs, early_stopping_accumulator, checkpoint_accumulator
):
    """
    Figure out what needs to be tracked/logged at the end of the epoch
    """

    # the training step outputs a list per optimizer. The list contains the outputs at each time step
    # when no TBPTT is used, then the list has 1 item per batch
    # when TBPTT IS used, then the list has n items (1 per time step)
    epoch_end_outputs = []
    for optimizer_idx_outputs in all_train_step_outputs:
        # extract one representative sample from each time step (1 if no tbptt) and 0th optimizer
        sample_output = optimizer_idx_outputs[-1]

        # pull out callback info if available (ie: Results object)
        if isinstance(sample_output, dict) and "early_stop_on" in sample_output:
            early_stopping_accumulator.accumulate(sample_output["early_stop_on"])

        if isinstance(sample_output, dict) and "checkpoint_on" in sample_output:
            checkpoint_accumulator.accumulate(sample_output["checkpoint_on"])

        # decide if we need to reduce at the end of the epoch automatically
        auto_reduce_tng_result = (
            isinstance(sample_output, Result)
            and sample_output.should_reduce_on_epoch_end
        )

        # only track when a) it needs to be autoreduced OR b) the user wants to manually reduce on epoch end
        if (
            is_overridden("training_epoch_end", model=self.trainer.get_model())
            or auto_reduce_tng_result
        ):
            epoch_end_outputs.append(optimizer_idx_outputs)

    return epoch_end_outputs


# Traceback (AttributeError)
...
File "/venv/lib/python3.6/site-packages/pytorch_lightning/trainer/training_loop.py", line 499, in run_training_epoch
│    self.run_training_epoch_end(epoch_output)
│  File "/venv/lib/python3.6/site-packages/pytorch_lightning/trainer/training_loop.py", line 533, in run_training_epoch_end
│    _processed_outputs = self.process_output(epoch_output)
│  File "/venv/lib/python3.6/site-packages/pytorch_lightning/trainer/logging.py", line 106, in process_output
│    for k, v in output.items():
│AttributeError: 'NoneType' object has no attribute 'items'
│Exception ignored in: <object repr() failed>
│Traceback (most recent call last):
│  File "/venv/lib/python3.6/site-packages/tqdm/std.py", line 1086, in __del__
│  File "/venv/lib/python3.6/site-packages/tqdm/std.py", line 1293, in close
│  File "/venv/lib/python3.6/site-packages/tqdm/std.py", line 1471, in display
│  File "/venv/lib/python3.6/site-packages/tqdm/std.py", line 1089, in __repr__
│  File "/venv/lib/python3.6/site-packages/tqdm/std.py", line 1433, in format_dict
│TypeError: 'NoneType' object is not iterable```

The fix that I've found is to return a dictionary according to the expected typed return, as follows:

# Fixed code
def process_train_step_outputs(
    self, all_train_step_outputs, early_stopping_accumulator, checkpoint_accumulator
):
    """
    Figure out what needs to be tracked/logged at the end of the epoch
    """

    # the training step outputs a list per optimizer. The list contains the outputs at each time step
    # when no TBPTT is used, then the list has 1 item per batch
    # when TBPTT IS used, then the list has n items (1 per time step)
    epoch_end_outputs = []
    for optimizer_idx_outputs in all_train_step_outputs:
        # extract one representative sample from each time step (1 if no tbptt) and 0th optimizer
        if len(optimizer_idx_outputs) == 0:
            continue

        sample_output = optimizer_idx_outputs[-1]

        # pull out callback info if available (ie: Results object)
        if isinstance(sample_output, dict) and "early_stop_on" in sample_output:
            early_stopping_accumulator.accumulate(sample_output["early_stop_on"])

        if isinstance(sample_output, dict) and "checkpoint_on" in sample_output:
            checkpoint_accumulator.accumulate(sample_output["checkpoint_on"])

        # decide if we need to reduce at the end of the epoch automatically
        auto_reduce_tng_result = (
            isinstance(sample_output, Result)
            and sample_output.should_reduce_on_epoch_end
        )

        # only track when a) it needs to be autoreduced OR b) the user wants to manually reduce on epoch end
        if (
            is_overridden("training_epoch_end", model=self.trainer.get_model())
            or auto_reduce_tng_result
        ):
            epoch_end_outputs.append(optimizer_idx_outputs)

    return epoch_end_outputs