-
Notifications
You must be signed in to change notification settings - Fork 919
CeleryGetter.get() returns non-string values, crashes TraceContext propagator #4359
Description
Description
CeleryGetter.get() can return non-string values (e.g. int) from Celery task request attributes, which causes TraceState.from_header() to crash with:
TypeError: expected string or bytes-like object, got 'int'
Stack trace
celery/utils/dispatch/signal.py:280 in send
opentelemetry/instrumentation/celery/__init__.py:174 in _trace_prerun
opentelemetry/propagate/__init__.py:101 in extract
opentelemetry/propagators/composite.py:52 in extract
opentelemetry/trace/propagation/tracecontext.py:76 in extract
opentelemetry/trace/span.py:386 in from_header
re/__init__.py:207 in split
TypeError: expected string or bytes-like object, got 'int'
Root cause
CeleryGetter.get() uses getattr(carrier, key, None) against task.request, which is a Celery Context object. Celery's Context.__init__ copies all message properties as instance attributes via self.__dict__.update(), including numeric values like timelimit.
When the value is an int, the existing type check wraps it in a tuple but doesn't coerce to string:
class CeleryGetter(Getter):
def get(self, carrier, key):
value = getattr(carrier, key, None)
if value is None:
return None
if isinstance(value, str) or not isinstance(value, Iterable):
value = (value,) # wraps int in tuple, but doesn't convert to str
return valueThe TextMapPropagator contract expects string values, and TraceState.from_header() passes each value directly to re.split() without type-checking.
Suggested fix
Coerce non-string values to strings in CeleryGetter.get():
def get(self, carrier, key):
value = getattr(carrier, key, None)
if value is None:
return None
if isinstance(value, str):
value = (value,)
elif isinstance(value, Iterable):
value = tuple(str(v) if not isinstance(v, str) else v for v in value)
else:
value = (str(value),)
return valueAlternatively, TraceState.from_header() could validate input types before calling re.split().
Environment
- opentelemetry-instrumentation-celery 0.61b0
- opentelemetry-sdk 1.x
- celery 5.x
- Python 3.12
Related
- celery instrumentation setting a single time limit (
soft_time_limitortime_limit) leads to warning: "Attribute 'celery.timelimit' mixes types str and int in attribute value sequence" #2022 (timelimit str/int mixing in span attributes — same root cause, different code path)