New-style errbacks in `_call_task_errbacks` are called with no exception handling — one failing errback silently halts the rest
Author: tejas-aeCreated Mar 13, 2026Updated Sep 17, 2026
In celery/backends/base.py, _call_task_errbacks handles two errback styles. New-style errbacks (those with __header__ and arity > 1) are invoked directly with no surrounding try/except:
# celery/backends/base.py, lines ~252-265
try:
if (
hasattr(errback.type, '__header__') and
not isinstance(errback.type.__header__, partial) and
arity_greater(errback.type.__header__, 1)
):
errback(request, exc, traceback) # <-- no exception handling
else:
old_signature.append(errback)
except NotRegistered:
old_signature.append(errback) # only NotRegistered is caughtIf a new-style errback raises any exception other than NotRegistered, that exception propagates uncaught, and subsequent errbacks in the chain are never called.
Compare with old-style errbacks (lines ~275-288), which do wrap execution in a try/except to log and continue.
Impact:
- A bug in errback A silently prevents errback B from running
- The exception may bubble up to the backend internals, causing unpredictable state
- There is no log entry indicating which errback failed
Questions:
- Is the missing exception handling in the new-style path an oversight, or is it intentional (i.e. new-style errbacks are trusted to be safe)?
- Should new-style errbacks be wrapped in the same defensive try/except as old-style ones, with an error log on failure?
- Is there a test covering the case where a new-style errback raises an unexpected exception?
File: celery/backends/base.py, lines 244–288.
Source: celery/celery