<p dir="auto">The body of a chord can be a task, a chain of tasks, or a group of tasks. In all of these cases, as expected, the result of the chord's header is passed to the body. However, if the body of a chord contains one or more chains, the return value of the chord's header is suddenly gone!</p>
<h2 dir="auto">Example application: canvastest.py</h2>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#!/usr/bin/env python
from celery import Celery

__all__ = ('app', 'ident')

app = Celery('canvastest.py', backend='redis://')

@app.task
def i(x):
    return x

if __name__ == '__main__':
    app.start()"><pre class="notranslate"><span class="pl-c">#!/usr/bin/env python</span>
<span class="pl-k">from</span> <span class="pl-s1">celery</span> <span class="pl-k">import</span> <span class="pl-v">Celery</span>

<span class="pl-s1">__all__</span> <span class="pl-c1">=</span> (<span class="pl-s">'app'</span>, <span class="pl-s">'ident'</span>)

<span class="pl-s1">app</span> <span class="pl-c1">=</span> <span class="pl-v">Celery</span>(<span class="pl-s">'canvastest.py'</span>, <span class="pl-s1">backend</span><span class="pl-c1">=</span><span class="pl-s">'redis://'</span>)

<span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-s1">task</span></span>
<span class="pl-k">def</span> <span class="pl-en">i</span>(<span class="pl-s1">x</span>):
    <span class="pl-k">return</span> <span class="pl-s1">x</span>

<span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">'__main__'</span>:
    <span class="pl-s1">app</span>.<span class="pl-en">start</span>()</pre></div>
<h2 dir="auto">Start the worker</h2>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ ./canvastest.py worker"><pre class="notranslate"><code class="notranslate">$ ./canvastest.py worker
</code></pre></div>
<h2 dir="auto">What works</h2>
<p dir="auto">The body of a chord can be a task, a chain of tasks, or a group of tasks. These all give the expected results:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ ./canvastest.py shell --python
&gt;&gt;&gt; chord([i.s(1), i.s(2)])(i.s()).get(timeout=5)
[1, 2]
&gt;&gt;&gt; chord([i.s(1), i.s(2)])(i.s() | i.s()).get(timeout=5)
[1, 2]
&gt;&gt;&gt; chord([i.s(1), i.s(2)])(group(i.s(), i.s())).get(timeout=5)
[[1, 2], [1, 2]]"><pre class="notranslate"><code class="notranslate">$ ./canvastest.py shell --python
&gt;&gt;&gt; chord([i.s(1), i.s(2)])(i.s()).get(timeout=5)
[1, 2]
&gt;&gt;&gt; chord([i.s(1), i.s(2)])(i.s() | i.s()).get(timeout=5)
[1, 2]
&gt;&gt;&gt; chord([i.s(1), i.s(2)])(group(i.s(), i.s())).get(timeout=5)
[[1, 2], [1, 2]]
</code></pre></div>
<h2 dir="auto">What's broken</h2>
<p dir="auto">It breaks if the body of the chord is a group that contains one or more chains. For some reason the result of the chord's header is lost.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; chord([i.s(1), i.s(2)])(group(i.s() | i.s(), i.s())).get(timeout=5)
...
TimeoutError: The operation timed out."><pre class="notranslate"><code class="notranslate">&gt;&gt;&gt; chord([i.s(1), i.s(2)])(group(i.s() | i.s(), i.s())).get(timeout=5)
...
TimeoutError: The operation timed out.
</code></pre></div>
<p dir="auto">Here is the error message from the worker:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[2017-07-25 22:16:31,904: ERROR/ForkPoolWorker-3] Chord callback for '769854f7-bda9-4fa4-a496-b0e03809c5fd' raised: TypeError('i() takes exactly 1 argument (0 given)',)
Traceback (most recent call last):
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/backends/redis.py&quot;, line 290, in on_chord_part_return
    callback.delay([unpack(tup, decode) for tup in resl])
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py&quot;, line 182, in delay
    return self.apply_async(partial_args, partial_kwargs)
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py&quot;, line 986, in apply_async
    args=args, kwargs=kwargs, **options))
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py&quot;, line 1062, in _apply_tasks
    **options)
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py&quot;, line 566, in apply_async
    dict(self.options, **options) if options else self.options))
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py&quot;, line 596, in run
    first_task.apply_async(**options)
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py&quot;, line 221, in apply_async
    return _apply(args, kwargs, **options)
  File &quot;/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/app/task.py&quot;, line 518, in apply_async
    check_arguments(*(args or ()), **(kwargs or {}))
TypeError: i() takes exactly 1 argument (0 given)"><pre class="notranslate"><code class="notranslate">[2017-07-25 22:16:31,904: ERROR/ForkPoolWorker-3] Chord callback for '769854f7-bda9-4fa4-a496-b0e03809c5fd' raised: TypeError('i() takes exactly 1 argument (0 given)',)
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/backends/redis.py", line 290, in on_chord_part_return
    callback.delay([unpack(tup, decode) for tup in resl])
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py", line 182, in delay
    return self.apply_async(partial_args, partial_kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py", line 986, in apply_async
    args=args, kwargs=kwargs, **options))
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py", line 1062, in _apply_tasks
    **options)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py", line 566, in apply_async
    dict(self.options, **options) if options else self.options))
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py", line 596, in run
    first_task.apply_async(**options)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/canvas.py", line 221, in apply_async
    return _apply(args, kwargs, **options)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/celery/app/task.py", line 518, in apply_async
    check_arguments(*(args or ()), **(kwargs or {}))
TypeError: i() takes exactly 1 argument (0 given)
</code></pre></div>
<p dir="auto">In the <a href="http://docs.celeryproject.org/en/latest/userguide/canvas.html#the-primitives" rel="nofollow">Documentations</a> says:</p>
<blockquote>
<p dir="auto">Groups and chords accepts partial arguments too, so in a chain the return value of the previous task is forwarded to all tasks in the group...</p>
</blockquote>
<p dir="auto">but it doesn't if group contain chain.</p>
<p dir="auto"><strong>Steps to reproduce</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# ct.py
from __future__ import absolute_import, unicode_literals
from celery import Celery

app = Celery(
    'ct',
    broker='amqp://guest@localhost//',
    backend='cache+memcached://127.0.0.1:11211/'
)

@app.task
def inc(x):
   x += 1
   return x

@app.task
def nothing(x):
   return x

if __name__ == '__main__':
    app.start()"><pre class="notranslate"><code class="notranslate"># ct.py
from __future__ import absolute_import, unicode_literals
from celery import Celery

app = Celery(
    'ct',
    broker='amqp://guest@localhost//',
    backend='cache+memcached://127.0.0.1:11211/'
)

@app.task
def inc(x):
   x += 1
   return x

@app.task
def nothing(x):
   return x

if __name__ == '__main__':
    app.start()
</code></pre></div>
<p dir="auto">Start worker:<br>
<code class="notranslate">python ct.py worker -l info</code></p>
<p dir="auto">In python console:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; from ct import inc, nothing
&gt;&gt;&gt; from celery import group, chain
&gt;&gt;&gt; t = chain(inc.s(),group(chain(nothing.s(), inc.s()), inc.s()))
&gt;&gt;&gt; r = t.delay(0)
&gt;&gt;&gt; "><pre class="notranslate"><code class="notranslate">&gt;&gt;&gt; from ct import inc, nothing
&gt;&gt;&gt; from celery import group, chain
&gt;&gt;&gt; t = chain(inc.s(),group(chain(nothing.s(), inc.s()), inc.s()))
&gt;&gt;&gt; r = t.delay(0)
&gt;&gt;&gt; 
</code></pre></div>
<p dir="auto">In <code class="notranslate">celery</code> log:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[2017-04-10 12:43:36,126: INFO/MainProcess] Received task: ct.inc[5c1beeff-d785-4d81-af2c-35a5bba839ab]  
[2017-04-10 12:43:37,257: WARNING/PoolWorker-1] /home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/trace.py:542: RuntimeWarning: Exception raised outside body: TypeError('nothing() takes exactly 1 argument (0 given)',):
Traceback (most recent call last):
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/trace.py&quot;, line 424, in trace_task
    parent_id=uuid, root_id=root_id,
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 987, in apply_async
    args=args, kwargs=kwargs, **options))
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 1063, in _apply_tasks
    **options)
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 567, in apply_async
    dict(self.options, **options) if options else self.options))
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 597, in run
    first_task.apply_async(**options)
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 221, in apply_async
    return _apply(args, kwargs, **options)
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/task.py&quot;, line 518, in apply_async
    check_arguments(*(args or ()), **(kwargs or {}))
TypeError: nothing() takes exactly 1 argument (0 given)

  exc, exc_info.traceback)))
[2017-04-10 12:43:37,262: ERROR/PoolWorker-1] Task ct.inc[5c1beeff-d785-4d81-af2c-35a5bba839ab] raised unexpected: TypeError('nothing() takes exactly 1 argument (0 given)',)
Traceback (most recent call last):
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/trace.py&quot;, line 424, in trace_task
    parent_id=uuid, root_id=root_id,
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 987, in apply_async
    args=args, kwargs=kwargs, **options))
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 1063, in _apply_tasks
    **options)
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 567, in apply_async
    dict(self.options, **options) if options else self.options))
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 597, in run
    first_task.apply_async(**options)
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py&quot;, line 221, in apply_async
    return _apply(args, kwargs, **options)
  File &quot;/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/task.py&quot;, line 518, in apply_async
    check_arguments(*(args or ()), **(kwargs or {}))
TypeError: nothing() takes exactly 1 argument (0 given)"><pre class="notranslate"><code class="notranslate">[2017-04-10 12:43:36,126: INFO/MainProcess] Received task: ct.inc[5c1beeff-d785-4d81-af2c-35a5bba839ab]  
[2017-04-10 12:43:37,257: WARNING/PoolWorker-1] /home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/trace.py:542: RuntimeWarning: Exception raised outside body: TypeError('nothing() takes exactly 1 argument (0 given)',):
Traceback (most recent call last):
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/trace.py", line 424, in trace_task
    parent_id=uuid, root_id=root_id,
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 987, in apply_async
    args=args, kwargs=kwargs, **options))
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 1063, in _apply_tasks
    **options)
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 567, in apply_async
    dict(self.options, **options) if options else self.options))
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 597, in run
    first_task.apply_async(**options)
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 221, in apply_async
    return _apply(args, kwargs, **options)
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/task.py", line 518, in apply_async
    check_arguments(*(args or ()), **(kwargs or {}))
TypeError: nothing() takes exactly 1 argument (0 given)

  exc, exc_info.traceback)))
[2017-04-10 12:43:37,262: ERROR/PoolWorker-1] Task ct.inc[5c1beeff-d785-4d81-af2c-35a5bba839ab] raised unexpected: TypeError('nothing() takes exactly 1 argument (0 given)',)
Traceback (most recent call last):
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/trace.py", line 424, in trace_task
    parent_id=uuid, root_id=root_id,
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 987, in apply_async
    args=args, kwargs=kwargs, **options))
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 1063, in _apply_tasks
    **options)
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 567, in apply_async
    dict(self.options, **options) if options else self.options))
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 597, in run
    first_task.apply_async(**options)
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/canvas.py", line 221, in apply_async
    return _apply(args, kwargs, **options)
  File "/home/vagrant/ct-env/local/lib/python2.7/site-packages/celery/app/task.py", line 518, in apply_async
    check_arguments(*(args or ()), **(kwargs or {}))
TypeError: nothing() takes exactly 1 argument (0 given)
</code></pre></div>
<p dir="auto"><strong>Expecting result</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; r.get()
[2, 2]"><pre class="notranslate"><code class="notranslate">&gt;&gt;&gt; r.get()
[2, 2]
</code></pre></div>
<p dir="auto"><strong>Celery info</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="celery -A ct report

software -&gt; celery:4.0.2 (latentcall) kombu:4.0.2 py:2.7.9
            billiard:3.5.0.2 py-amqp:2.1.4
platform -&gt; system:Linux arch:64bit, ELF imp:CPython
loader   -&gt; celery.loaders.app.AppLoader
settings -&gt; transport:amqp results:cache+memcached://127.0.0.1:11211/

broker_url: u'amqp://guest:********@localhost:5672//'
result_backend: u'cache+memcached://127.0.0.1:11211/'
"><pre class="notranslate"><code class="notranslate">celery -A ct report

software -&gt; celery:4.0.2 (latentcall) kombu:4.0.2 py:2.7.9
            billiard:3.5.0.2 py-amqp:2.1.4
platform -&gt; system:Linux arch:64bit, ELF imp:CPython
loader   -&gt; celery.loaders.app.AppLoader
settings -&gt; transport:amqp results:cache+memcached://127.0.0.1:11211/

broker_url: u'amqp://guest:********@localhost:5672//'
result_backend: u'cache+memcached://127.0.0.1:11211/'

</code></pre></div>
<p dir="auto"><strong>Notes</strong></p>
<p dir="auto">Work fine with Celery 3.x</p>