From github problem # 1881 , if the callback has a link_error parameter that accepts a list of task names, then when the chord task is not running, link_error tasks will be executed.
@task(name='super_task.good') def good(): return True @task(name='super_task.raise_exception') def raise_exception(): raise ValueError('error') @task(name='super_task.callback') def callback(*args, **kwargs): logger.info('callback') logger.info(args) logger.info(kwargs) return 'finished' @task(name='super_task.error_callback') def error_callback(*args, **kwargs): logger.info('error_callback') logger.info(args) logger.info(kwargs) return 'error' >>> c = chord( [raise_exception.s(), good.s(), raise_exception.s()], callback.s().set(link_error=['super_task.error_callback']) ) >>> result = c()
This will lead to a chord and in your celery log, you will see that the raise_exception task will fail, and the error_callback that will be received in it will call task_id from callback .
At this point, the result value will contain an AsyncResult callback instance, but because in the chord the errors propagate to the callback, making result.get() will result in the exception of tasks and result.traceback gives you a trace.
If you want to have one callback, just pass the chord callback name to link_error
callback.s().set(link_error='super_task.callback')
NOTE
Another option is to set CELERY_CHORD_PROPAGATES = False , which will return to atrial 3.1 behavior and will always call back.
But this is not recommended because, as you can find in github issue # 1349
Celery 3.1 determines how chordal errors are handled, previous behavior has never been documented and more of an accident, since it was never intended to work that way.
We could not change the behavior in the patch release, so instead we had to set a parameter, but there was never an intention for someone to consciously disable the new behavior.
New behavior exists to protect against this kind of problem, and remote compatibility can be removed. I suggest you find another way to handle errors here (and I would not mind the suggestion if you can come up with a good api for it)