# Buggy code
def normalize_chunk_sizes(shape, chunk_size):
    shape = normalize_shape(shape)
    if not isinstance(chunk_size, tuple):
        if isinstance(chunk_size, Iterable):
            chunk_size = tuple(chunk_size)
        elif isinstance(chunk_size, int):
            chunk_size = (chunk_size,) * len(shape)

    if len(shape) != len(chunk_size):
        raise ValueError(
            "Chunks must have the same dimemsion, "
            f"got shape: {shape}, chunks: {chunk_size}"
        )

    chunk_sizes = []
    for size, chunk in zip(shape, chunk_size):
        if isinstance(chunk, Iterable):
            if not isinstance(chunk, tuple):
                chunk = tuple(chunk)

            if sum(chunk) != size:
                raise ValueError(
                    "chunks shape should be of the same length, "
                    f"got shape: {size}, chunks: {chunk}"
                )
            chunk_sizes.append(chunk)
        else:
            assert isinstance(chunk, int)

            sizes = tuple(chunk for _ in range(int(size / chunk))) + (
                tuple() if size % chunk == 0 else (size % chunk,)
            )
            chunk_sizes.append(sizes)

    return tuple(chunk_sizes)


# Traceback (TilesError)
In [1]: import pandas as pd

In [2]: a = pd.DataFrame(columns=list('ab'))

In [3]: import mars.dataframe as md

In [4]: md.DataFrame(a).iloc[:2].execute()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-4-426db4e594a4> in <module>
----> 1 md.DataFrame(a).iloc[:2].execute()

~/Documents/mars_dev/mars/mars/core.py in execute(self, session, **kw)
576
577     def execute(self, session=None, **kw):
--> 578         self._data.execute(session, **kw)
579         return self
580

~/Documents/mars_dev/mars/mars/core.py in execute(self, session, **kw)
364
365         # no more fetch, thus just fire run
--> 366         session.run(self, **kw)
367         # return Tileable or ExecutableTuple itself
368         return self

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
478         tileables = tuple(mt.tensor(t) if not isinstance(t, (Entity, Base)) else t
479                           for t in tileables)
--> 480         result = self._sess.run(*tileables, **kw)
481
482         for t in tileables:

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
105             # set number of running cores
106             self.context.set_ncores(kw['n_parallel'])
--> 107             res = self._executor.execute_tileables(tileables, **kw)
108             return res
109

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
406                 _kernel_mode.eager = False
407             _kernel_mode.eager_count = enter_eager_count + 1
--> 408             return func(*args, **kwargs)
409         finally:
410             _kernel_mode.eager_count -= 1

~/Documents/mars_dev/mars/mars/utils.py in inner(*args, **kwargs)
500     def inner(*args, **kwargs):
501         with build_mode():
--> 502             return func(*args, **kwargs)
503     return inner
504

~/Documents/mars_dev/mars/mars/executor.py in execute_tileables(self, tileables, fetch, n_parallel, n_thread, print_progress, mock, compose, name)
862                 # build chunk graph, tile will be done during building
863                 chunk_graph = chunk_graph_builder.build(
--> 864                     tileables, tileable_graph=tileable_graph)
865                 tileable_graph = chunk_graph_builder.prev_tileable_graph
866                 temp_result_keys = set(result_keys)

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
406                 _kernel_mode.eager = False
407             _kernel_mode.eager_count = enter_eager_count + 1
--> 408             return func(*args, **kwargs)
409         finally:
410             _kernel_mode.eager_count -= 1

~/Documents/mars_dev/mars/mars/utils.py in inner(*args, **kwargs)
500     def inner(*args, **kwargs):
501         with build_mode():
--> 502             return func(*args, **kwargs)
503     return inner
504

~/Documents/mars_dev/mars/mars/tiles.py in build(self, tileables, tileable_graph)
348
349         chunk_graph = super().build(
--> 350             tileables, tileable_graph=tileable_graph)
351         self._iterative_chunk_graphs.append(chunk_graph)
352         if len(self._interrupted_ops) == 0:

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
406                 _kernel_mode.eager = False
407             _kernel_mode.eager_count = enter_eager_count + 1
--> 408             return func(*args, **kwargs)
409         finally:
410             _kernel_mode.eager_count -= 1

~/Documents/mars_dev/mars/mars/utils.py in inner(*args, **kwargs)
500     def inner(*args, **kwargs):
501         with build_mode():
--> 502             return func(*args, **kwargs)
503     return inner
504

~/Documents/mars_dev/mars/mars/tiles.py in build(self, tileables, tileable_graph)
261                     # for further execution
262                     partial_tiled_chunks = \
--> 263                         self._on_tile_failure(tileable_data.op, exc_info)
264                     if partial_tiled_chunks is not None and \
265                             len(partial_tiled_chunks) > 0:

~/Documents/mars_dev/mars/mars/tiles.py in inner(op, exc_info)
300                     on_tile_failure(op, exc_info)
301                 else:
--> 302                     raise exc_info[1].with_traceback(exc_info[2]) from None
303         return inner
304

~/Documents/mars_dev/mars/mars/tiles.py in build(self, tileables, tileable_graph)
241                 continue
242             try:
--> 243                 tiled = self._tile(tileable_data, tileable_graph)
244                 tiled_op.add(tileable_data.op)
245                 for t, td in zip(tileable_data.op.outputs, tiled):

~/Documents/mars_dev/mars/mars/tiles.py in _tile(self, tileable_data, tileable_graph)
336         if any(inp.op in self._interrupted_ops for inp in tileable_data.inputs):
337             raise TilesError('Tile fail due to failure of inputs')
--> 338         return super()._tile(tileable_data, tileable_graph)
339
340     @kernel_mode

~/Documents/mars_dev/mars/mars/tiles.py in _tile(self, tileable_data, tileable_graph)
199                 t._nsplits = o.nsplits
200         elif on_tile is None:
--> 201             tds[0]._inplace_tile()
202         else:
203             tds = on_tile(tileable_data.op.outputs, tds)

~/Documents/mars_dev/mars/mars/core.py in _inplace_tile(self)
161
162     def _inplace_tile(self):
--> 163         return handler.inplace_tile(self)
164
165     def __getattr__(self, attr):

~/Documents/mars_dev/mars/mars/tiles.py in inplace_tile(self, to_tile)
134         if not to_tile.is_coarse():
135             return to_tile
--> 136         dispatched = self.dispatch(to_tile.op)
137         self._assign_to([d.data for d in dispatched], to_tile.op.outputs)
138         return to_tile

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
406                 _kernel_mode.eager = False
407             _kernel_mode.eager_count = enter_eager_count + 1
--> 408             return func(*args, **kwargs)
409         finally:
410             _kernel_mode.eager_count -= 1

~/Documents/mars_dev/mars/mars/tiles.py in dispatch(self, op)
117         else:
118             try:
--> 119                 tiled = op_cls.tile(op)
120             except NotImplementedError as ex:
121                 cause = ex

~/Documents/mars_dev/mars/mars/dataframe/indexing/iloc.py in tile(cls, op)
339
340         handler = DataFrameIlocIndexesHandler()
--> 341         return [handler.handle(op)]
342
343     @classmethod

~/Documents/mars_dev/mars/mars/tensor/indexing/index_lib.py in handle(self, op, return_context)
896
897         self._preprocess(context, index_infos)
--> 898         self._process(context, index_infos)
899         self._postprocess(context, index_infos)
900

~/Documents/mars_dev/mars/mars/tensor/indexing/index_lib.py in _process(cls, context, index_infos)
923         index_to_shape = OrderedDict(sorted([(c.index, c.shape) for c in out_chunks],
924                                             key=itemgetter(0)))
--> 925         context.out_nsplits = calc_nsplits(index_to_shape)
926
927     @classmethod

~/Documents/mars_dev/mars/mars/utils.py in calc_nsplits(chunk_idx_to_shape)
664     :return: nsplits
665     """
--> 666     ndim = len(next(iter(chunk_idx_to_shape)))
667     tileable_nsplits = []
668     # for each dimension, record chunk shape whose index is zero on other dimensions

StopIteration:

# Fixed code
def normalize_chunk_sizes(shape, chunk_size):
    shape = normalize_shape(shape)
    if not isinstance(chunk_size, tuple):
        if isinstance(chunk_size, Iterable):
            chunk_size = tuple(chunk_size)
        elif isinstance(chunk_size, int):
            chunk_size = (chunk_size,) * len(shape)

    if len(shape) != len(chunk_size):
        raise ValueError(
            "Chunks must have the same dimemsion, "
            f"got shape: {shape}, chunks: {chunk_size}"
        )

    chunk_sizes = []
    for size, chunk in zip(shape, chunk_size):
        if isinstance(chunk, Iterable):
            if not isinstance(chunk, tuple):
                chunk = tuple(chunk)

            if sum(chunk) != size:
                raise ValueError(
                    "chunks shape should be of the same length, "
                    f"got shape: {size}, chunks: {chunk}"
                )
            chunk_sizes.append(chunk)
        else:
            assert isinstance(chunk, int)

            if size == 0:
                sizes = (0,)
            else:
                sizes = tuple(chunk for _ in range(int(size / chunk))) + (
                    tuple() if size % chunk == 0 else (size % chunk,)
                )
            chunk_sizes.append(sizes)

    return tuple(chunk_sizes)