# Buggy code
def get_new_columns(self):
    if self.value_columns is None:
        if self.lift == 0:
            return self.removed_level

        lev = self.removed_level
        return lev.insert(0, _get_na_value(lev.dtype.type))

    stride = len(self.removed_level) + self.lift
    width = len(self.value_columns)
    propagator = np.repeat(np.arange(width), stride)
    if isinstance(self.value_columns, MultiIndex):
        new_levels = self.value_columns.levels + (self.removed_level,)
        new_names = self.value_columns.names + (self.removed_name,)

        new_labels = [lab.take(propagator) for lab in self.value_columns.labels]
    else:
        new_levels = [self.value_columns, self.removed_level]
        new_names = [self.value_columns.name, self.removed_name]
        new_labels = [propagator]

    new_labels.append(np.tile(np.arange(stride) - self.lift, width))
    return MultiIndex(
        levels=new_levels, labels=new_labels, names=new_names, verify_integrity=False
    )


# 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 get_new_columns(self):
    if self.value_columns is None:
        if self.lift == 0:
            return self.removed_level

        lev = self.removed_level
        return lev.insert(0, _get_na_value(lev.dtype.type))

    stride = len(self.removed_level) + self.lift
    width = len(self.value_columns)
    propagator = np.repeat(np.arange(width), stride)
    if isinstance(self.value_columns, MultiIndex):
        new_levels = self.value_columns.levels + (self.removed_level_full,)
        new_names = self.value_columns.names + (self.removed_name,)

        new_labels = [lab.take(propagator) for lab in self.value_columns.labels]
    else:
        new_levels = [self.value_columns, self.removed_level_full]
        new_names = [self.value_columns.name, self.removed_name]
        new_labels = [propagator]

    # The two indices differ only if the unstacked level had unused items:
    if len(self.removed_level_full) != len(self.removed_level):
        # In this case, we remap the new labels to the original level:
        repeater = self.removed_level_full.get_indexer(self.removed_level)
        if self.lift:
            repeater = np.insert(repeater, 0, -1)
    else:
        # Otherwise, we just use each level item exactly once:
        repeater = np.arange(stride) - self.lift

    # The entire level is then just a repetition of the single chunk:
    new_labels.append(np.tile(repeater, width))
    return MultiIndex(
        levels=new_levels, labels=new_labels, names=new_names, verify_integrity=False
    )