Conversation
Omp-Session: 01a06876-38b6-7000-bab9-630cf784a742
Collaborator
Author
|
Production recurrence data for this fix (Trajectory Labs deployment, 2026-09-10):
Each failure drops the observability event for that request, which is the data loss this PR prevents. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On 2026-09-09, PostgreSQL JSONB writes dropped conversation events and request logs when captured content contained U+0000. Those losses remove the affected session tail from history, activity monitoring, and judge transcripts.
Production evidence
The
/ecs/luthien-proxylog group recordedasyncpg.exceptions.UntranslatableCharacterError('unsupported Unicode escape sequence')fromconversation_events.payloadwrites. The event writer dropped 8 events at 11:43Z, about 135 from 13:24Z to 13:27Z, and about 100 from 19:13Z to 21:01Z. Its in-process counter read 111 at 21:01Z. Datadog APM recorded 28 matchingINSERTerror spans in the preceding hour and sevenluthien_proxy.utils.db.DatabaseWriteErrorspans.Mechanism and fix
json.dumpsescapes U+0000 as\u0000, which PostgreSQL JSONB rejects. A shared write-boundary serializer now converts JSON-compatible values, replaces every NUL in keys and values with U+FFFD, and adds_sanitized: {"nul_replaced": N}to dict payloads. BothEventEmitterandRequestLogRecorderuse it immediately before JSON serialization. Database-drop warnings now identify the call ID, session ID, and event type or request-log direction.Verification
Unit regression coverage verifies nested keys and values, non-string leaves, the stored marker, SQLite event storage, request-log headers and bodies, and attributed warnings:
78 passed.A PostgreSQL integration test persisted an event containing NUL characters and read back U+FFFD plus
_sanitized:1 passed.Red check with the sanitizer bypassed produced the original failed-write behavior:
PYTEST_ADDOPTS='--ignore=tests/luthien_proxy/e2e_tests' ./scripts/dev_checks.shcompleted with Ruff and Pyright clean. The default test selection already excludes the e2e tier; this also prevents its collection-time shared.envloader from changing unit-test configuration.