fix(ai): sanitize base64 content in $ai_trace/$ai_span input/output state - #4196
Conversation
|
cc @PostHog/team-ai-observability |
|
cc @PostHog/team-ai-observability |
carlos-marchal-ph
left a comment
There was a problem hiding this comment.
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!
can you force push your commits with verified signatures so we can merge this |
e1a9325 to
671bab9
Compare
…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>
|
@marandaneto Done — rebased onto latest |
Problem
_setLLMMetadataruns generation input throughsanitizeLangChain(BinaryContentRedactor), but_popRunAndCaptureTraceOrSpancapturesrun.inputandoutputsraw 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:The whole batch POST is dropped after retries — including unrelated
$exceptionevents queued alongside, which silently degrades error tracking. In short-lived runtimes (Supabase edge functions) the timer-driven flush rejection also surfaced as an uncaughtevent loop error, terminating the worker.Observed on
@posthog/ai8.2.1; the gap is still present onmain.Fix
Apply
sanitizeLangChainto$ai_input_stateand$ai_output_stateat 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
[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