# Buggy code
def maybe_casted_values(index, codes=None):
    """
    Convert an index, given directly or as a pair (level, code), to a 1D array.

    Parameters
    ----------
    index : Index
    codes : sequence of integers (optional)

    Returns
    -------
    ExtensionArray or ndarray
        If codes is `None`, the values of `index`.
        If codes is passed, an array obtained by taking from `index` the indices
        contained in `codes`.
    """

    values = index._values
    if not isinstance(index, (ABCPeriodIndex, ABCDatetimeIndex)):
        if values.dtype == np.object_:
            values = lib.maybe_convert_objects(values)

    # if we have the codes, extract the values with a mask
    if codes is not None:
        mask = codes == -1

        # we can have situations where the whole mask is -1,
        # meaning there is nothing found in codes, so make all nan's
        if mask.size > 0 and mask.all():
            dtype = index.dtype
            fill_value = na_value_for_dtype(dtype)
            values = construct_1d_arraylike_from_scalar(fill_value, len(mask), dtype)
        else:
            values = values.take(codes)

            # TODO(https://github.com/pandas-dev/pandas/issues/24206)
            # Push this into maybe_upcast_putmask?
            # We can't pass EAs there right now. Looks a bit
            # complicated.
            # So we unbox the ndarray_values, op, re-box.
            values_type = type(values)
            values_dtype = values.dtype

            from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin

            if isinstance(values, DatetimeLikeArrayMixin):
                values = values._data  # TODO: can we de-kludge yet?

            if mask.any():
                values, _ = maybe_upcast_putmask(values, mask, np.nan)

            if issubclass(values_type, DatetimeLikeArrayMixin):
                values = values_type(values, dtype=values_dtype)

    return values


# Traceback (TypeError)
In [29]: idx = pd.MultiIndex([pd.CategoricalIndex(['A', 'B']), pd.CategoricalIndex(['a', 'b'])], [[0, 0, 1, 1], [0, 1, 0, -1]])

In [30]: df = pd.DataFrame({'col': range(len(idx))}, index=idx)

In [31]: df
Out[31]:
col
A a      0
b      1
B a      2
NaN    3

In [32]: df.reset_index()
/home/joris/miniconda3/lib/python3.5/site-packages/pandas/core/frame.py:4091: FutureWarning: Interpreting negative values in 'indexer' as missing values.
In the future, this will change to meaning positional indicies
from the right.

Use 'allow_fill=True' to retain the previous behavior and silence this
warning.

Use 'allow_fill=False' to accept the new behavior.
values = values.take(labels)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/miniconda3/lib/python3.5/site-packages/pandas/core/dtypes/cast.py in maybe_upcast_putmask(result, mask, other)
249         try:
--> 250             np.place(result, mask, other)
251         except Exception:

~/miniconda3/lib/python3.5/site-packages/numpy/lib/function_base.py in place(arr, mask, vals)
2371         raise TypeError("argument 1 must be numpy.ndarray, "
-> 2372                         "not {name}".format(name=type(arr).__name__))
2373

TypeError: argument 1 must be numpy.ndarray, not Categorical

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-32-6983677cc901> in <module>()
----> 1 df.reset_index()

~/miniconda3/lib/python3.5/site-packages/pandas/core/frame.py in reset_index(self, level, drop, inplace, col_level, col_fill)
4136                     name = tuple(name_lst)
4137                 # to ndarray and maybe infer different dtype
-> 4138                 level_values = _maybe_casted_values(lev, lab)
4139                 new_obj.insert(0, name, level_values)
4140

~/miniconda3/lib/python3.5/site-packages/pandas/core/frame.py in _maybe_casted_values(index, labels)
4092                     if mask.any():
4093                         values, changed = maybe_upcast_putmask(
-> 4094                             values, mask, np.nan)
4095             return values
4096

~/miniconda3/lib/python3.5/site-packages/pandas/core/dtypes/cast.py in maybe_upcast_putmask(result, mask, other)
250             np.place(result, mask, other)
251         except Exception:
--> 252             return changeit()
253
254     return result, False

~/miniconda3/lib/python3.5/site-packages/pandas/core/dtypes/cast.py in changeit()
222             # isn't compatible
223             r, _ = maybe_upcast(result, fill_value=other, copy=True)
--> 224             np.place(r, mask, other)
225
226             return r, True

~/miniconda3/lib/python3.5/site-packages/numpy/lib/function_base.py in place(arr, mask, vals)
2370     if not isinstance(arr, np.ndarray):
2371         raise TypeError("argument 1 must be numpy.ndarray, "
-> 2372                         "not {name}".format(name=type(arr).__name__))
2373
2374     return _insert(arr, mask, vals)

TypeError: argument 1 must be numpy.ndarray, not Categorical

# Fixed code
def maybe_casted_values(index, codes=None):
    """
    Convert an index, given directly or as a pair (level, code), to a 1D array.

    Parameters
    ----------
    index : Index
    codes : sequence of integers (optional)

    Returns
    -------
    ExtensionArray or ndarray
        If codes is `None`, the values of `index`.
        If codes is passed, an array obtained by taking from `index` the indices
        contained in `codes`.
    """

    values = index._values
    if not isinstance(index, (ABCPeriodIndex, ABCDatetimeIndex)):
        if values.dtype == np.object_:
            values = lib.maybe_convert_objects(values)

    # if we have the codes, extract the values with a mask
    if codes is not None:
        mask = codes == -1

        # we can have situations where the whole mask is -1,
        # meaning there is nothing found in codes, so make all nan's
        if mask.size > 0 and mask.all():
            dtype = index.dtype
            fill_value = na_value_for_dtype(dtype)
            values = construct_1d_arraylike_from_scalar(fill_value, len(mask), dtype)
        else:
            values = values.take(codes)

            # TODO(https://github.com/pandas-dev/pandas/issues/24206)
            # Push this into maybe_upcast_putmask?
            # We can't pass EAs there right now. Looks a bit
            # complicated.
            # So we unbox the ndarray_values, op, re-box.
            values_type = type(values)
            values_dtype = values.dtype

            from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin

            if isinstance(values, DatetimeLikeArrayMixin):
                values = values._data  # TODO: can we de-kludge yet?

            if mask.any():
                if isinstance(values, np.ndarray):
                    values, _ = maybe_upcast_putmask(values, mask, np.nan)
                else:
                    values[mask] = np.nan

            if issubclass(values_type, DatetimeLikeArrayMixin):
                values = values_type(values, dtype=values_dtype)

    return values