# Buggy code
def tile(cls, op):
    tensor = op.outputs[0]
    chunk_size = tensor.extra_params.raw_chunk_size or options.chunk_size
    nsplits = decide_chunk_sizes(tensor.shape, chunk_size, tensor.dtype.itemsize)
    fields = getattr(op, "_input_fields_", [])
    to_one_chunk_fields = set(getattr(op, "_into_one_chunk_fields_", list()))

    new_inputs = []
    changed = False
    for field in fields:
        t = getattr(op, field)
        if not isinstance(t, TENSOR_TYPE):
            continue

        if field not in to_one_chunk_fields:
            t_nsplits = nsplits
        else:
            t_nsplits = t.shape  # into 1 chunk
        rechunked = t.rechunk(t_nsplits)
        if rechunked is not t:
            rechunked._inplace_tile()
            changed = True
            new_inputs.append(rechunked)
        else:
            new_inputs.append(t)
    if changed:
        op.inputs = new_inputs

    idxes = list(itertools.product(*[range(len(s)) for s in nsplits]))
    seeds = gen_random_seeds(len(idxes), op.state)

    out_chunks = []
    for seed, idx, shape in zip(seeds, idxes, itertools.product(*nsplits)):
        inputs = []
        for inp in op.inputs:
            if len(inp.chunks) == 1:
                inputs.append(inp.chunks[0])
            else:
                inputs.append(inp.cix[idx])
        try:
            s = len(tuple(op.size))
            size = shape[:s]
        except TypeError:
            if op.size is None:
                size = None
            else:
                size = shape[:1]
        except AttributeError:
            size = shape

        chunk_op = op.copy().reset_key()
        chunk_op._seed = seed
        chunk_op._state = None
        chunk_op._size = size
        out_chunk = chunk_op.new_chunk(
            inputs, shape=shape, index=idx, order=tensor.order
        )
        out_chunks.append(out_chunk)

    new_op = op.copy()
    return new_op.new_tensors(
        op.inputs,
        tensor.shape,
        order=tensor.order,
        chunks=out_chunks,
        nsplits=nsplits,
        **tensor.extra_params,
    )


# Traceback (AttributeError)
In [3]: import pandas as pd

In [4]: data = pd.DataFrame(np.arange(20).reshape((4, 5)) + 1, columns=['a', 'b', 'c', 'd', 'e'])

In [6]: df = md.DataFrame(data)

In [7]: df.groupby(['a','b']).size().execute()
Unexpected exception occurred in enter_build_mode.<locals>.inner.
Traceback (most recent call last):
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 353, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 493, in inner
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/scheduler/graph.py", line 633, in prepare_graph
self._target_tileable_datas + fetch_tileables, tileable_graph)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 399, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 493, in inner
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 350, in build
tileables, tileable_graph=tileable_graph)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 399, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 493, in inner
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 263, in build
self._on_tile_failure(tileable_data.op, exc_info)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 302, in inner
raise exc_info[1].with_traceback(exc_info[2]) from None
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 243, in build
tiled = self._tile(tileable_data, tileable_graph)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 338, in _tile
return super()._tile(tileable_data, tileable_graph)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 203, in _tile
tds = on_tile(tileable_data.op.outputs, tds)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/scheduler/graph.py", line 615, in on_tile
return self.context.wraps(handler.dispatch)(first.op)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/context.py", line 69, in h
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 399, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/tiles.py", line 119, in dispatch
tiled = op_cls.tile(op)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/dataframe/groupby/aggregation.py", line 481, in tile
return cls._tile_with_tree(op)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/dataframe/groupby/aggregation.py", line 412, in _tile_with_tree
index = out_df.index_value.to_pandas()
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/dataframe/core.py", line 283, in to_pandas
return self._index_value.to_pandas()
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/dataframe/core.py", line 197, in to_pandas
sortorder=self._sortorder, names=self._names)
AttributeError: _sortorder

# Fixed code
def tile(cls, op):
    tensor = op.outputs[0]
    chunk_size = tensor.extra_params.raw_chunk_size or options.chunk_size
    nsplits = decide_chunk_sizes(tensor.shape, chunk_size, tensor.dtype.itemsize)
    fields = getattr(op, "_input_fields_", [])
    to_one_chunk_fields = set(getattr(op, "_into_one_chunk_fields_", list()))

    new_inputs = []
    changed = False
    for field in fields:
        t = getattr(op, field)
        if not isinstance(t, TENSOR_TYPE):
            continue

        if field not in to_one_chunk_fields:
            t_nsplits = nsplits
        else:
            t_nsplits = t.shape  # into 1 chunk
        rechunked = t.rechunk(t_nsplits)
        if rechunked is not t:
            rechunked._inplace_tile()
            changed = True
            new_inputs.append(rechunked)
        else:
            new_inputs.append(t)
    if changed:
        op.inputs = new_inputs

    idxes = list(itertools.product(*[range(len(s)) for s in nsplits]))
    seeds = gen_random_seeds(len(idxes), op.state)

    out_chunks = []
    for seed, idx, shape in zip(seeds, idxes, itertools.product(*nsplits)):
        inputs = []
        for inp in op.inputs:
            if len(inp.chunks) == 1:
                inputs.append(inp.chunks[0])
            else:
                inputs.append(inp.cix[idx])
        try:
            s = len(tuple(op.size))
            size = shape[:s]
        except TypeError:
            if op.size is None:
                size = None
            else:
                size = shape[:1]
        except AttributeError:
            size = shape

        chunk_op = op.copy().reset_key()
        chunk_op._seed = int(seed)
        chunk_op._state = None
        chunk_op._size = size
        out_chunk = chunk_op.new_chunk(
            inputs, shape=shape, index=idx, order=tensor.order
        )
        out_chunks.append(out_chunk)

    new_op = op.copy()
    return new_op.new_tensors(
        op.inputs,
        tensor.shape,
        order=tensor.order,
        chunks=out_chunks,
        nsplits=nsplits,
        **tensor.extra_params,
    )