Which component is this bug for?
Anthropic Instrumentation
📜 Description
When the Anthropic instrumentation is run in event-logging mode (use_legacy_attributes=False, with an event_logger_provider configured), a messages.create() call that omits tools causes the emitted GenAI input event to contain the Anthropic SDK sentinel anthropic.NOT_GIVEN in its log record Body. The OTLP log exporter cannot serialize anthropic.NotGiven, so the entire log batch fails to export with:
opentelemetry.sdk._shared_internal - ERROR - Exception while exporting Log.
...
Exception: Invalid type <class 'anthropic.NotGiven'> of value NOT_GIVEN
Root cause
In opentelemetry/instrumentation/anthropic/event_emitter.py, emit_input_events():
if kwargs.get("system"): # truthiness — NOT_GIVEN is falsy, correctly skipped
emit_event(MessageEvent(content=kwargs.get("system"), role="system"), event_logger)
for message in kwargs.get("messages"):
emit_event(MessageEvent(content=message.get("content"), role=message.get("role")), event_logger)
if kwargs.get("tools") is not None: # BUG: `is not None` lets NOT_GIVEN through
emit_event(
MessageEvent(content={"tools": kwargs.get("tools")}, role="user"), # NOT_GIVEN placed in Body
event_logger,
)
When a caller omits tools, the Anthropic SDK passes tools=anthropic.NOT_GIVEN. NOT_GIVEN is not None evaluates to True, so the guard passes and the sentinel object is put verbatim into the MessageEvent body
({"tools": NOT_GIVEN}). It then flows into the OTel LogRecord body, and the OTLP protobuf encoder
(opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder) raises on the unsupported type.
Note the inconsistency: the system branch immediately above uses a truthiness check (if kwargs.get("system"):), which correctly drops NOT_GIVEN (bool(NOT_GIVEN) is False). Only the tools branch uses is not None, so
only tools leaks the sentinel.
👟 Reproduction steps
- Instrument Anthropic in event mode with an OTLP log exporter:
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
from opentelemetry.sdk._events import EventLoggerProvider
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
logger_provider = LoggerProvider()
logger_provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter()))
AnthropicInstrumentor().instrument(
event_logger_provider=EventLoggerProvider(logger_provider),
)
# equivalent to use_legacy_attributes=False + event logging enabled
- Make a
messages.create() call without the tools argument (so the SDK defaults it to NOT_GIVEN):
import anthropic
client = anthropic.Anthropic()
client.messages.create(
model="claude-sonnet-4-...",
max_tokens=256,
system="You are a helpful assistant.",
messages=[{"role": "user", "content": "Hi"}],
# note: no `tools=` argument
)
- On the next log batch export, the exporter crashes with
Invalid type <class 'anthropic.NotGiven'> of value NOT_GIVEN and the batch is dropped.
👍 Expected behavior
Omitted optional parameters (represented by anthropic.NOT_GIVEN) should not be emitted into event bodies. The input event should simply not include a tools entry when no tools were passed — mirroring the existing system handling.
👎 Actual Behavior with Screenshots
MessageEvent(content={"tools": NOT_GIVEN}, role="user") is emitted, placing a non-serializable anthropic.NotGiven into the OTel log Body. The OTLP log exporter then fails to encode the batch and all log records in that batch are lost. A full traceback is logged on every export interval.
🤖 Python Version
3.13
📃 Provide any additional context for the Bug.
Suggested fix
Guard tools with a truthiness check, consistent with system (handles both
NOT_GIVEN and empty lists):
if kwargs.get("tools"): # NOT_GIVEN and [] are both falsy → skipped
emit_event(
MessageEvent(content={"tools": kwargs.get("tools")}, role="user"),
event_logger,
)
(Alternatively, sanitize all NOT_GIVEN values out of kwargs before building events, which also future-proofs emit_response_events and any other sentinel leakage.)
Stack trace
opentelemetry.sdk._shared_internal - ERROR - Exception while exporting Log.
Traceback (most recent call last):
File ".../opentelemetry/sdk/_shared_internal/__init__.py", line 179, in _export
self._exporter.export(...)
File ".../opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py", line 116, in export
return OTLPExporterMixin._export(self, batch)
File ".../opentelemetry/exporter/otlp/proto/grpc/exporter.py", line 392, in _export
request=self._translate_data(data),
File ".../opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py", line 110, in _translate_data
return encode_logs(data)
File ".../_log_encoder/__init__.py", line 58, in _encode_log
body=_encode_value(body, allow_null=True),
File ".../_internal/__init__.py", line 95, in _encode_value
_encode_key_value(str(k), v, allow_null=allow_null)
File ".../_internal/__init__.py", line 107, in _encode_key_value
key=key, value=_encode_value(value, allow_null=allow_null)
File ".../_internal/__init__.py", line 100, in _encode_value
raise Exception(f"Invalid type {type(value)} of value {value}")
Exception: Invalid type <class 'anthropic.NotGiven'> of value NOT_GIVEN
Additional context
- Surfaced via kagent (v0.9.6), which enables event-mode GenAI logging and routes events to an OTLP
LoggerProvider. The crash reproduces on the direct Anthropic API path.
- It reliably fires on requests with no tools — e.g. ADK's event-compaction summarizer call (which sends no tools) — while normal tool-carrying turns serialize fine.
- Functional impact is limited to telemetry: the LLM calls themselves succeed (HTTP 200); only the GenAI log export is lost, plus recurring traceback noise. Traces (separate exporter) are unaffected.
Versions
opentelemetry-instrumentation-anthropic: 0.52.5
anthropic: 0.104.1
opentelemetry-exporter-otlp-proto-common: 1.38.0
👀 Have you spent some time to check if this bug has been raised before?
Are you willing to submit PR?
None
Which component is this bug for?
Anthropic Instrumentation
📜 Description
When the Anthropic instrumentation is run in event-logging mode (
use_legacy_attributes=False, with anevent_logger_providerconfigured), amessages.create()call that omitstoolscauses the emitted GenAI input event to contain the Anthropic SDK sentinelanthropic.NOT_GIVENin its log record Body. The OTLP log exporter cannot serializeanthropic.NotGiven, so the entire log batch fails to export with:Root cause
In
opentelemetry/instrumentation/anthropic/event_emitter.py,emit_input_events():When a caller omits
tools, the Anthropic SDK passestools=anthropic.NOT_GIVEN.NOT_GIVEN is not Noneevaluates toTrue, so the guard passes and the sentinel object is put verbatim into theMessageEventbody(
{"tools": NOT_GIVEN}). It then flows into the OTelLogRecordbody, and the OTLP protobuf encoder(
opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder) raises on the unsupported type.Note the inconsistency: the
systembranch immediately above uses a truthiness check (if kwargs.get("system"):), which correctly dropsNOT_GIVEN(bool(NOT_GIVEN)isFalse). Only thetoolsbranch usesis not None, soonly
toolsleaks the sentinel.👟 Reproduction steps
messages.create()call without thetoolsargument (so the SDK defaults it toNOT_GIVEN):Invalid type <class 'anthropic.NotGiven'> of value NOT_GIVENand the batch is dropped.👍 Expected behavior
Omitted optional parameters (represented by
anthropic.NOT_GIVEN) should not be emitted into event bodies. The input event should simply not include atoolsentry when no tools were passed — mirroring the existingsystemhandling.👎 Actual Behavior with Screenshots
MessageEvent(content={"tools": NOT_GIVEN}, role="user")is emitted, placing a non-serializableanthropic.NotGiveninto the OTel log Body. The OTLP log exporter then fails to encode the batch and all log records in that batch are lost. A full traceback is logged on every export interval.🤖 Python Version
3.13
📃 Provide any additional context for the Bug.
Suggested fix
Guard
toolswith a truthiness check, consistent withsystem(handles bothNOT_GIVENand empty lists):(Alternatively, sanitize all
NOT_GIVENvalues out ofkwargsbefore building events, which also future-proofsemit_response_eventsand any other sentinel leakage.)Stack trace
Additional context
LoggerProvider. The crash reproduces on the direct Anthropic API path.Versions
opentelemetry-instrumentation-anthropic:0.52.5anthropic:0.104.1opentelemetry-exporter-otlp-proto-common:1.38.0👀 Have you spent some time to check if this bug has been raised before?
Are you willing to submit PR?
None