Skip to content

fix(ai_guard): fix blocked requests not appearing in APM and LLM Observability for langchain 1.x#18555

Open
avara1986 wants to merge 3 commits into
mainfrom
fix/ai-guard-block-trace-dropped-langgraph-langchain
Open

fix(ai_guard): fix blocked requests not appearing in APM and LLM Observability for langchain 1.x#18555
avara1986 wants to merge 3 commits into
mainfrom
fix/ai-guard-block-trace-dropped-langgraph-langchain

Conversation

@avara1986

@avara1986 avara1986 commented Jun 10, 2026

Copy link
Copy Markdown
Member

Description

AI Guard DENY/ABORT responses raise AIGuardAbortError, which is a BaseException subclass (not Exception). The LangGraph pregel stream generators used except Exception in their inner loops, so span.finish() was never called when a block propagated — causing the entire trace to be silently dropped from APM, LLM Observability, and the AI Guard UI.

Fix:

  • Widen except Exceptionexcept BaseException in the 5 LangGraph generator catch sites (traced_runnable_seq_invoke, traced_runnable_seq_ainvoke, _astream in traced_runnable_seq_astream, _stream in traced_pregel_stream, _astream in traced_pregel_astream)
  • Add DDBlockException to the except tuple in the LangChain LCEL wrappers (traced_lcel_runnable_sequence, traced_lcel_runnable_sequence_async) so set_exc_info is called for blocked requests

Jira: APPSEC-68351

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codeowners resolved as

ddtrace/contrib/internal/langgraph/patch.py                             @DataDog/ml-observability

@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 8 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-py | build linux serverless: [amd64, cp315-cp315, v113741238-d2b8243-manylinux2014_x86_64, 1]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux serverless: [amd64, cp315-cp315, v113741491-d2b8243-musllinux_1_2_x86_64, 1]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux serverless: [arm64, cp315-cp315, v113741357-d2b8243-manylinux2014_aarch64, 1]   View in Datadog   GitLab

View all 8 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 1 job - 1 passed on retry View in Datadog

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: b98a73c | Docs | Datadog PR Page | Give us feedback!

…errors

The langgraph tracing handlers were changed to `except BaseException` so
AI Guard's DDBlockException (a BaseException subclass) would still finish
the span. But in the stream generators that catch also swallowed
GeneratorExit (break/close/aclose) and CancelledError, marking normal
stream teardown as span errors. Narrow the catch to
(DDBlockException, Exception), mirroring the LangChain integration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@avara1986 avara1986 marked this pull request as ready for review June 10, 2026 10:53
@avara1986 avara1986 requested review from a team as code owners June 10, 2026 10:53
assert mock_execute_request.call_count == 3


@requires_create_agent

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this defined?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's defined at the top of this same file (line 35):

requires_create_agent = pytest.mark.skipif(
    LANGCHAIN_VERSION < (1, 0, 0),
    reason="create_agent API introduced in langchain 1.0",
)

It mirrors requires_legacy_agents right above it — langchain 1.0 dropped the legacy AgentExecutor API in favor of the langgraph-based create_agent, so the suite is version-split.

inputs = [inputs]
final_output = func(*args, **kwargs)
except Exception:
except (DDBlockException, Exception):

@Yun-Kim Yun-Kim Jun 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DDBlockException is a subclass of BaseException I am assuming? What was the reason for that out of curiosity?

@avara1986 avara1986 Jun 10, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! AIGuardAbortError -> DDBlockException -> BaseException (not Exception). That's intentional: AI Guard's DENY/ABORT verdict needs to propagate out of user agent code without being accidentally swallowed by a generic except Exception: (which is extremely common in LLM/agent loops). Since it sits as a sibling of Exception rather than a subclass, we have to list both in the tuple here to run set_exc_info for the blocked case while still catching ordinary errors.

Comment on lines +198 to +202
# AIDEV-NOTE: catch ``DDBlockException`` explicitly (parent of ``AIGuardAbortError``) since it inherits
# from ``BaseException`` — otherwise an AI Guard abort would slip past ``except Exception:`` and the span
# would never get ``set_exc_info`` / ``finish``. We must NOT catch bare ``BaseException`` here: this wraps
# a ``yield``, so normal stream teardown (``break`` / ``close()`` / ``aclose()`` -> ``GeneratorExit``) and
# async cancellation (``CancelledError``) would otherwise be mis-reported as span errors.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is unnecessary and explained from the code itself

@avara1986 avara1986 Jun 10, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trimmed it down

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants