# Buggy code
def execute_tileables(
    self,
    tileables,
    fetch=True,
    n_parallel=None,
    n_thread=None,
    print_progress=False,
    mock=False,
    compose=True,
):
    graph = DirectedGraph()

    result_keys = []
    to_release_keys = []
    concat_keys = []
    for tileable in tileables:
        tileable.tiles()
        chunk_keys = [c.key for c in tileable.chunks]
        result_keys.extend(chunk_keys)

        if tileable.key in self.stored_tileables:
            self.stored_tileables[tileable.key][0].add(tileable.id)
        else:
            self.stored_tileables[tileable.key] = tuple(
                [{tileable.id}, set(chunk_keys)]
            )
        if not fetch:
            # no need to generate concat keys
            pass
        elif len(tileable.chunks) > 1:
            # if need to fetch data and chunks more than 1, we concatenate them into 1
            tileable = concat_tileable_chunks(tileable)
            chunk = tileable.chunks[0]
            result_keys.append(chunk.key)
            # the concatenated key
            concat_keys.append(chunk.key)
            # after return the data to user, we release the reference
            to_release_keys.append(chunk.key)
        else:
            concat_keys.append(tileable.chunks[0].key)

        tileable.build_graph(
            graph=graph,
            tiled=True,
            compose=compose,
            executed_keys=list(self._chunk_result.keys()),
        )

    self.execute_graph(
        graph,
        result_keys,
        n_parallel=n_parallel or n_thread,
        print_progress=print_progress,
        mock=mock,
    )

    results = self._chunk_result
    try:
        if fetch:
            return [results[k] for k in concat_keys]
        else:
            return
    finally:
        for k in to_release_keys:
            del results[k]


# Traceback (InvalidComposedNodeError)
In [1]: import mars.tensor as mt

In [2]: a = mt.random.rand(4, 4) + 1 - 3

In [3]: u, s, v = mt.linalg.svd(a)

In [4]: (u + 1).execute()
Out[4]:
array([[0.53491564, 0.50844154, 1.31934217, 0.33660917],
[0.48043745, 0.58359388, 1.12894514, 1.73486995],
[0.54248881, 1.05235106, 0.12344775, 0.86000348],
[0.4482439 , 1.76304364, 1.33622891, 0.98327479]])

In [5]: (u + 2).execute()
---------------------------------------------------------------------------
InvalidComposedNodeError                  Traceback (most recent call last)
<ipython-input-5-1dd2365be547> in <module>
----> 1 (u + 2).execute()

~/Documents/mars_dev/mars/mars/tensor/core.py in execute(self, session, **kw)
442
443     def execute(self, session=None, **kw):
--> 444         return self._data.execute(session, **kw)
445
446

~/Documents/mars_dev/mars/mars/core.py in execute(self, session, **kw)
572         if session is None:
573             session = Session.default_or_local()
--> 574         return session.run(self, **kw)
575
576     def fetch(self, session=None, **kw):

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
150         tileables = tuple(mt.tensor(t) if not isinstance(t, (Entity, Base)) else t
151                           for t in tileables)
--> 152         result = self._sess.run(*tileables, **kw)
153
154         for t in tileables:

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
61         if 'n_parallel' not in kw:
62             kw['n_parallel'] = cpu_count()
---> 63         res = self._executor.execute_tileables(tileables, **kw)
64         return res
65

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
389                 _kernel_mode.eager = False
390             _kernel_mode.eager_count = enter_eager_count + 1
--> 391             return func(*args, **kwargs)
392         finally:
393             _kernel_mode.eager_count -= 1

~/Documents/mars_dev/mars/mars/executor.py in execute_tileables(self, tileables, fetch, n_parallel, n_thread, print_progress, mock, compose)
548
549         self.execute_graph(graph, result_keys, n_parallel=n_parallel or n_thread,
--> 550                            print_progress=print_progress, mock=mock)
551
552         results = self._chunk_result

~/Documents/mars_dev/mars/mars/executor.py in execute_graph(self, graph, keys, n_parallel, print_progress, mock, no_intermediate, compose, retval)
469         :return: execution result
470         """
--> 471         optimized_graph = self._preprocess(graph, keys) if compose else graph
472
473         if not mock:

~/Documents/mars_dev/mars/mars/executor.py in _preprocess(self, graph, keys)
435         from .optimizes.core import Optimizer
436
--> 437         Optimizer(graph, self._engine).optimize(keys=keys)
438         return graph
439

~/Documents/mars_dev/mars/mars/optimizes/core.py in optimize(self, keys)
32
33     def optimize(self, keys=None):
---> 34         self._graph.decompose()
35         if self._engine == 'numpy':
36             return

~/Documents/mars_dev/mars/mars/graph.pyx in mars.graph.DirectedGraph.decompose()

~/Documents/mars_dev/mars/mars/fuse.pyx in mars.fuse.Fusion.decompose()

~/Documents/mars_dev/mars/mars/fuse.pyx in mars.fuse.Fusion._decompose_node()

InvalidComposedNodeError: Invalid composed node data

# Fixed code
def execute_tileables(
    self,
    tileables,
    fetch=True,
    n_parallel=None,
    n_thread=None,
    print_progress=False,
    mock=False,
    compose=True,
):
    graph = DirectedGraph()

    result_keys = []
    to_release_keys = []
    concat_keys = []
    for tileable in tileables:
        tileable.tiles()
        chunk_keys = [c.key for c in tileable.chunks]
        result_keys.extend(chunk_keys)

        if tileable.key in self.stored_tileables:
            self.stored_tileables[tileable.key][0].add(tileable.id)
        else:
            self.stored_tileables[tileable.key] = tuple(
                [{tileable.id}, set(chunk_keys)]
            )
        if not fetch:
            # no need to generate concat keys
            pass
        elif len(tileable.chunks) > 1:
            # if need to fetch data and chunks more than 1, we concatenate them into 1
            tileable = concat_tileable_chunks(tileable)
            chunk = tileable.chunks[0]
            result_keys.append(chunk.key)
            # the concatenated key
            concat_keys.append(chunk.key)
            # after return the data to user, we release the reference
            to_release_keys.append(chunk.key)
        else:
            concat_keys.append(tileable.chunks[0].key)

        # Do not do compose here, because building graph has not finished yet
        tileable.build_graph(
            graph=graph,
            tiled=True,
            compose=False,
            executed_keys=list(self._chunk_result.keys()),
        )
    if compose:
        # finally do compose according to option
        graph.compose(
            keys=list(itertools.chain(*[[c.key for c in t.chunks] for t in tileables]))
        )

    self.execute_graph(
        graph,
        result_keys,
        n_parallel=n_parallel or n_thread,
        print_progress=print_progress,
        mock=mock,
    )

    results = self._chunk_result
    try:
        if fetch:
            return [results[k] for k in concat_keys]
        else:
            return
    finally:
        for k in to_release_keys:
            del results[k]