# Buggy code
def _copartition(self, axis, other, how, sort, force_repartition=False):
    """
    Copartition two dataframes.

    Parameters
    ----------
        axis : 0 or 1
            The axis to copartition along (0 - rows, 1 - columns).
        other : BasePandasFrame
            The other dataframes(s) to copartition against.
        how : str
            How to manage joining the index object ("left", "right", etc.)
        sort : boolean
            Whether or not to sort the joined index.
        force_repartition : boolean
            Whether or not to force the repartitioning. By default,
            this method will skip repartitioning if it is possible. This is because
            reindexing is extremely inefficient. Because this method is used to
            `join` or `append`, it is vital that the internal indices match.

    Returns
    -------
    Tuple
        A tuple (left data, right data list, joined index).
    """
    if isinstance(other, type(self)):
        other = [other]

    index_other_obj = [o.axes[axis] for o in other]
    joined_index = self._join_index_objects(axis, index_other_obj, how, sort)
    # We have to set these because otherwise when we perform the functions it may
    # end up serializing this entire object.
    left_old_idx = self.axes[axis]
    right_old_idxes = index_other_obj

    # Start with this and we'll repartition the first time, and then not again.
    if not left_old_idx.equals(joined_index) or force_repartition:
        reindexed_self = self._frame_mgr_cls.map_axis_partitions(
            axis, self._partitions, lambda df: df.reindex(joined_index, axis=axis)
        )
    else:
        reindexed_self = self._partitions
    reindexed_other_list = []

    for i in range(len(other)):
        if right_old_idxes[i].equals(joined_index) and not force_repartition:
            reindexed_other = other[i]._partitions
        else:
            reindexed_other = other[i]._frame_mgr_cls.map_axis_partitions(
                axis,
                other[i]._partitions,
                lambda df: df.reindex(joined_index, axis=axis),
            )
        reindexed_other_list.append(reindexed_other)
    return reindexed_self, reindexed_other_list, joined_index


# Traceback (Exception)
UserWarning: Distributing <class 'list'> object. This may take some time.

In [4]: df
Out[4]: ---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/core/formatters.py in __call__(self, obj)
700                 type_pprinters=self.type_printers,
701                 deferred_pprinters=self.deferred_printers)
--> 702             printer.pretty(obj)
703             printer.flush()
704             return stream.getvalue()

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/lib/pretty.py in pretty(self, obj)
400                         if cls is not object \
401                                 and callable(cls.__dict__.get('__repr__')):
--> 402                             return _repr_pprint(obj, self, cycle)
403
404             return _default_pprint(obj, self, cycle)

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
695     """A pprint that just redirects to the normal repr function."""
696     # Find newlines and replace them with p.break_()
--> 697     output = repr(obj)
698     for idx,output_line in enumerate(output.splitlines()):
699         if idx:

~/software_builds/modin/modin/pandas/dataframe.py in __repr__(self)
168
169             num_cols += len(self.columns) - i
--> 170         result = repr(self._build_repr_df(num_rows, num_cols))
171         if len(self.index) > num_rows or len(self.columns) > num_cols:
172             # The split here is so that we don't repr pandas row lengths.

~/software_builds/modin/modin/pandas/base.py in _build_repr_df(self, num_rows, num_cols)
117         else:
118             indexer = row_indexer
--> 119         return self.iloc[indexer]._query_compiler.to_pandas()
120
121     def _update_inplace(self, new_query_compiler):

~/software_builds/modin/modin/backends/pandas/query_compiler.py in to_pandas(self)
193
194     def to_pandas(self):
--> 195         return self._modin_frame.to_pandas()
196
197     @classmethod

~/software_builds/modin/modin/engines/base/frame/data.py in to_pandas(self)
1816             ErrorMessage.catch_bugs_and_request_email(
1817                 not df.index.equals(self.index) or not df.columns.equals(self.columns),
-> 1818                 "Internal and external indices do not match.",
1819             )
1820             df.index = self.index

~/software_builds/modin/modin/error_message.py in catch_bugs_and_request_email(cls, failure_condition, extra_log)
52                 "Internal Error. "
53                 "Please email bug_reports@modin.org with the traceback and command that"
---> 54                 " caused this error.\n{}".format(extra_log)
55             )
56

Exception: Internal Error. Please email bug_reports@modin.org with the traceback and command that caused this error.
Internal and external indices do not match.

# Fixed code
def _copartition(self, axis, other, how, sort, force_repartition=False):
    """
    Copartition two dataframes.

    Parameters
    ----------
        axis : 0 or 1
            The axis to copartition along (0 - rows, 1 - columns).
        other : BasePandasFrame
            The other dataframes(s) to copartition against.
        how : str
            How to manage joining the index object ("left", "right", etc.)
        sort : boolean
            Whether or not to sort the joined index.
        force_repartition : boolean
            Whether or not to force the repartitioning. By default,
            this method will skip repartitioning if it is possible. This is because
            reindexing is extremely inefficient. Because this method is used to
            `join` or `append`, it is vital that the internal indices match.

    Returns
    -------
    Tuple
        A tuple (left data, right data list, joined index).
    """
    if isinstance(other, type(self)):
        other = [other]
    if all(o.axes[axis].equals(self.axes[axis]) for o in other):
        return (
            self._partitions,
            [self._simple_shuffle(axis, o) for o in other],
            self.axes[axis].copy(),
        )
    index_other_obj = [o.axes[axis] for o in other]
    joined_index = self._join_index_objects(axis, index_other_obj, how, sort)
    # We have to set these because otherwise when we perform the functions it may
    # end up serializing this entire object.
    left_old_idx = self.axes[axis]
    right_old_idxes = index_other_obj

    # Start with this and we'll repartition the first time, and then not again.
    if not left_old_idx.equals(joined_index) or force_repartition:
        reindexed_self = self._frame_mgr_cls.map_axis_partitions(
            axis, self._partitions, lambda df: df.reindex(joined_index, axis=axis)
        )
    else:
        reindexed_self = self._partitions
    reindexed_other_list = []

    for i in range(len(other)):
        if right_old_idxes[i].equals(joined_index) and not force_repartition:
            reindexed_other = other[i]._partitions
        else:
            reindexed_other = other[i]._frame_mgr_cls.map_axis_partitions(
                axis,
                other[i]._partitions,
                lambda df: df.reindex(joined_index, axis=axis),
            )
        reindexed_other_list.append(reindexed_other)
    return reindexed_self, reindexed_other_list, joined_index