Skip to content

[BUG] LangChain tool spans store raw RunnableConfig in metadata, crashing agentless trace encoding #18561

Description

@simonline

Summary

LangChainIntegration._llmobs_set_meta_tags_from_tool stores the tool invocation config dict directly in span metadata without sanitization:

if tool_inputs.get("config"):
    metadata["tool_config"] = tool_inputs.get("config")

When the tool is executed by a LangGraph agent, this config is a RunnableConfig containing non-JSON-serializable objects, for example functools.partial (under configurable.__pregel_send) and AsyncCallbackManager (under callbacks). In agentless mode the JSON trace encoder then raises on flush and the entire trace payload is dropped:

TypeError: Object of type AsyncCallbackManager is not JSON serializable
  File ".../ddtrace/internal/encoding.py", line 211, in put
    encoded_trace = _json_dumps_bytes({"spans": [...]})

Depending on the graph wiring, the failing object can also be functools.partial. Every trace containing at least one LangGraph tool execution is lost, which makes LLM Observability silently blind for agent workloads in agentless setups.

Reproduction

  • ddtrace 4.10.1, Python 3.12, langgraph + langchain-core current releases
  • LLMObs.enable(agentless_enabled=True, ...) with the LangChain integration active
  • Build any LangGraph StateGraph with a ToolNode and invoke it so a tool runs
  • On span flush, the writer raises the TypeError above and drops the trace

Expected behavior

tool_config should go through the same safe_json sanitization that the integration already applies to tool arguments and I/O values in the neighbouring code paths.

Suggested fix

if tool_inputs.get("config"):
    metadata["tool_config"] = json.loads(safe_json(tool_inputs.get("config")))

Workaround

Wrapping _llmobs_set_meta_tags_from_tool to sanitize tool_inputs["config"] via safe_json before delegating to the original restores trace delivery.

Metadata

Metadata

Assignees

No one assigned

    Labels

    LLMObsLLM Observability related

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions