# Buggy code
def __init__(
    self, values, index, level=-1, value_columns=None, fill_value=None, constructor=None
):
    self.is_categorical = None
    self.is_sparse = is_sparse(values)
    if values.ndim == 1:
        if isinstance(values, Categorical):
            self.is_categorical = values
            values = np.array(values)
        elif self.is_sparse:
            # XXX: Makes SparseArray *dense*, but it's supposedly
            # a single column at a time, so it's "doable"
            values = values.values
        values = values[:, np.newaxis]
    self.values = values
    self.value_columns = value_columns
    self.fill_value = fill_value

    if constructor is None:
        if self.is_sparse:
            self.constructor = SparseDataFrame
        else:
            self.constructor = DataFrame
    else:
        self.constructor = constructor

    if value_columns is None and values.shape[1] != 1:  # pragma: no cover
        raise ValueError("must pass column labels for multi-column data")

    self.index = index

    self.level = self.index._get_level_number(level)

    # when index includes `nan`, need to lift levels/strides by 1
    self.lift = 1 if -1 in self.index.labels[self.level] else 0

    self.new_index_levels = list(index.levels)
    self.new_index_names = list(index.names)

    self.removed_name = self.new_index_names.pop(self.level)
    self.removed_level = self.new_index_levels.pop(self.level)

    self._make_sorted_values_labels()
    self._make_selectors()


# Traceback (AssertionError)
In [2]: df = pd.DataFrame([[2009, 1, 15, 'City1', 'Housing'],
...:                    [2010, 2, np.nan, 'City2', 'Housing']],
...:                   columns=['year', 'month', 'day', 'city', 'sector'])
...:

In [3]: df['day'] = 15
...: df['date'] = pd.to_datetime(df[['year', 'month', 'day']])
...:

In [4]: ind = df.set_index(['date', 'sector', 'city'], drop=False).sort_index()

In [5]:

In [5]: cols = ['month', 'year', 'sector']
...: per_city = ind.loc[(slice(None), slice(None), 'City1'), cols].dropna(how='any')
...:

In [6]: per_city.unstack()
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-6-97028d1092eb> in <module>()
----> 1 per_city.unstack()

/home/nobackup/repo/pandas/pandas/core/frame.py in unstack(self, level, fill_value)
4575         """
4576         from pandas.core.reshape.reshape import unstack
-> 4577         return unstack(self, level, fill_value)
4578
4579     _shared_docs['melt'] = ("""

/home/nobackup/repo/pandas/pandas/core/reshape/reshape.py in unstack(obj, level, fill_value)
463     if isinstance(obj, DataFrame):
464         if isinstance(obj.index, MultiIndex):
--> 465             return _unstack_frame(obj, level, fill_value=fill_value)
466         else:
467             return obj.T.stack(dropna=False)

/home/nobackup/repo/pandas/pandas/core/reshape/reshape.py in _unstack_frame(obj, level, fill_value)
476         unstacker = partial(_Unstacker, index=obj.index,
477                             level=level, fill_value=fill_value)
--> 478         blocks = obj._data.unstack(unstacker)
479         klass = type(obj)
480         return klass(blocks)

/home/nobackup/repo/pandas/pandas/core/internals.py in unstack(self, unstacker_func)
4374         new_columns = new_columns[columns_mask]
4375
-> 4376         bm = BlockManager(new_blocks, [new_columns, new_index])
4377         return bm
4378

/home/nobackup/repo/pandas/pandas/core/internals.py in __init__(self, blocks, axes, do_integrity_check, fastpath)
3042         self._consolidate_check()
3043
-> 3044         self._rebuild_blknos_and_blklocs()
3045
3046     def make_empty(self, axes=None):

/home/nobackup/repo/pandas/pandas/core/internals.py in _rebuild_blknos_and_blklocs(self)
3134
3135         if (new_blknos == -1).any():
-> 3136             raise AssertionError("Gaps in blk ref_locs")
3137
3138         self._blknos = new_blknos

AssertionError: Gaps in blk ref_locs

# Fixed code
def __init__(
    self, values, index, level=-1, value_columns=None, fill_value=None, constructor=None
):
    self.is_categorical = None
    self.is_sparse = is_sparse(values)
    if values.ndim == 1:
        if isinstance(values, Categorical):
            self.is_categorical = values
            values = np.array(values)
        elif self.is_sparse:
            # XXX: Makes SparseArray *dense*, but it's supposedly
            # a single column at a time, so it's "doable"
            values = values.values
        values = values[:, np.newaxis]
    self.values = values
    self.value_columns = value_columns
    self.fill_value = fill_value

    if constructor is None:
        if self.is_sparse:
            self.constructor = SparseDataFrame
        else:
            self.constructor = DataFrame
    else:
        self.constructor = constructor

    if value_columns is None and values.shape[1] != 1:  # pragma: no cover
        raise ValueError("must pass column labels for multi-column data")

    self.index = index.remove_unused_levels()

    self.level = self.index._get_level_number(level)

    # when index includes `nan`, need to lift levels/strides by 1
    self.lift = 1 if -1 in self.index.labels[self.level] else 0

    self.new_index_levels = list(self.index.levels)
    self.new_index_names = list(self.index.names)

    self.removed_name = self.new_index_names.pop(self.level)
    self.removed_level = self.new_index_levels.pop(self.level)
    self.removed_level_full = index.levels[self.level]

    self._make_sorted_values_labels()
    self._make_selectors()