Skip to content

fix(ai): sanitize base64 content in $ai_trace/$ai_span input/output state - #4196

Merged
marandaneto merged 1 commit into
PostHog:mainfrom
reclaim-admin:fix/sanitize-trace-span-state
Jul 28, 2026
Merged

fix(ai): sanitize base64 content in $ai_trace/$ai_span input/output state#4196
marandaneto merged 1 commit into
PostHog:mainfrom
reclaim-admin:fix/sanitize-trace-span-state

Conversation

@reclaim-admin

Copy link
Copy Markdown
Contributor

Problem

_setLLMMetadata runs generation input through sanitizeLangChain (BinaryContentRedactor), but _popRunAndCaptureTraceOrSpan captures run.input and outputs raw into $ai_input_state / $ai_output_state.

Since every withStructuredOutput().invoke() (and any chain) emits a $ai_trace/$ai_span, an image call embeds its full base64 data URLs in the trace event. In production we observed 1–4.5 MB events that ingest rejects with:

HTTP 413 — maximum event size exceeded: Event rejected by kafka during send

The whole batch POST is dropped after retries — including unrelated $exception events queued alongside, which silently degrades error tracking. In short-lived runtimes (Supabase edge functions) the timer-driven flush rejection also surfaced as an uncaught event loop error, terminating the worker.

Observed on @posthog/ai 8.2.1; the gap is still present on main.

Fix

Apply sanitizeLangChain to $ai_input_state and $ai_output_state at capture time in _popRunAndCaptureTraceOrSpan, mirroring the generation path. Sanitizing at the capture site covers all sources that feed _setTraceOrSpanMetadata (chains, tools, retrievers, agent actions).

Testing

  • New regression test: a chain start/end carrying a base64 image data URL asserts both state properties contain [base64 image/jpeg redacted] (and not the payload) while normal text survives.
  • tests/callbacks.test.ts (14 passed), tests/sanitization.test.ts + tests/binary_content_redactor.test.ts (90 passed).

🤖 Generated with Claude Code

@ioannisj
ioannisj requested a review from a team July 25, 2026 10:44
@marandaneto

Copy link
Copy Markdown
Member

cc @PostHog/team-ai-observability

@marandaneto

Copy link
Copy Markdown
Member

cc @PostHog/team-ai-observability

@carlos-marchal-ph carlos-marchal-ph left a comment

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.

Hi @reclaim-admin, thanks for the contribution! We are actually working on a big refactor for the sanitisation plumbing (already up for review for Python), that should fix not only this issue, but many adjacent ones. Hoping to get it out early this week, merging this for the moment as it is the correct fix for this specific issue!

@marandaneto

Copy link
Copy Markdown
Member

@reclaim-admin

Commits must have verified signatures.

can you force push your commits with verified signatures so we can merge this

@reclaim-admin
reclaim-admin force-pushed the fix/sanitize-trace-span-state branch from e1a9325 to 671bab9 Compare July 27, 2026 20:40
…tate

_setLLMMetadata runs generation input through sanitizeLangChain, but
_popRunAndCaptureTraceOrSpan captured run.input and outputs raw. A
withStructuredOutput().invoke() with image content therefore emits a
$ai_trace event embedding every base64 data URL — multi-MB events that
ingest rejects with 413 "maximum event size exceeded", dropping the
entire batch (including unrelated $exception events queued with it).

Apply sanitizeLangChain to $ai_input_state and $ai_output_state at
capture time, mirroring the generation path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com>
@reclaim-admin reclaim-admin reopened this Jul 27, 2026
@reclaim-admin

Copy link
Copy Markdown
Contributor Author

@marandaneto Done — rebased onto latest main and squashed into a single verified commit (7b76817), including your changeset and formatting fixes (kept you as co-author). Should be good to merge now. Apologies for the brief auto-close, that was a side effect of the force-push.

@marandaneto
marandaneto merged commit b96a066 into PostHog:main Jul 28, 2026
51 checks passed
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