Repository navigation
fix(tracing): serialize non-string propagated metadata as JSON - #1945
Closed
niklassemmler wants to merge 3 commits into
Closed
niklassemmler wants to merge 3 commits into
niklassemmler wants to merge 3 commits into
Conversation
propagate_attributes coerced non-string trace metadata values with str(), so
lists, tuples and dicts were stored as Python reprs (`['branch:agent']`,
`('root', 'agent')`) that are not valid JSON, booleans became `True`, and
None became the string `None`.
Serialize non-string values as compact JSON instead, and skip None values.
Strings are unchanged. The 200 character limit applies to the serialized
value.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@claude review |
There was a problem hiding this comment.
Claude Code Review
No review was started: this request came from a bot account. Manual reviews can only be requested by someone with write access to this repository. Ask a maintainer to comment @claude review, or have your automation post the comment from a user account with write access.
Tip: disable this comment in your organization's Code Review settings.
json.dumps escapes non-ASCII characters as \uXXXX by default, so a list or dict value with non-ASCII text counted up to 6 characters per character against the 200 character limit and was dropped. Serialize with ensure_ascii=False, which also matches JSON.stringify output in the JS SDK. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@claude review 🤖 Written by Claude (an AI agent) on behalf of Niklas |
Contributor
Author
|
Closing in favor of #1932, which JSON-serializes propagated metadata values on |
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.
Sibling of #1944 (LFE-17153). #1944 moves observation metadata to one JSON attribute and leaves propagated trace metadata per-key. This PR fixes how the per-key trace metadata values are encoded.
Problem
propagate_attributes(metadata=...)coerces non-string values withstr()(propagation.py). The server stores per-key trace metadata (langfuse.trace.metadata.<key>) as the raw string without parsing it, so Python reprs end up in storage:["branch:agent"]['branch:agent']["branch:agent"]("root", "agent")('root', 'agent')["root","agent"]{"model": "gpt-4"}{'model': 'gpt-4'}{"model":"gpt-4"}TrueTruetruedatetime(2024, 1, 1, tzinfo=utc)2024-01-01 00:00:00+00:00"2024-01-01T00:00:00Z"NoneNone1,0.5,"text"1,0.5,textThis hits LangChain/LangGraph users in particular: the callback handler forwards run metadata such as
langgraph_triggersandlanggraph_pathtopropagate_attributes.Change
EventSerializer(same serializer and separators as observation metadata in feat(tracing)!: send observation metadata as one JSON attribute #1944). Strings are kept as they are.Nonevalues are skipped instead of being stored as"None", matching how observation metadata treatsNone.Behavior change to call out
Stored values change for non-string trace metadata (see table). Saved filters on the old repr values (e.g.
enabled = True,langgraph_triggers = ['branch:agent']) won't match new data. Strings and numbers, the common case, are unchanged. This ships asfix, but it could ride along with the #1944 major if reviewers prefer to group stored-value changes.Parity with langfuse-js
JS
propagateAttributestakesRecord<string, string>and drops non-string values with a warning. Python keeps coercing on purpose:test_non_string_metadata_values_coercedpins coercion for LangGraph keys. This PR doesn't change that decision, it only makes the coerced value valid JSON. Whether both SDKs should coerce to JSON or both drop non-strings is an open question for the metadata workstream.Verification
uv run --frozen ruff check .✅uv run --frozen ruff format✅uv run --frozen mypy langfuse --no-error-summary✅Expected ... ["branch:agent"], got ['branch:agent'], andNonestored as an attribute).uv run --frozen pytest -n auto --dist worksteal tests/unit --deselect tests/unit/test_prompt.py: 690 passed ✅tests/unit/test_prompt.py: 18 errors, same onmain(Langfuse client is not initialized, a local env issue).tests/e2e: not run, no Langfuse server available.🤖 Generated with Claude Code
The PR appears safe to merge with its explicitly acknowledged stored-value changes.
What we checked:
EventSerializercatches encoding errors and returns a fallback string. Its depth limit also bounds circular collections.propagation.pyalready importsattributes.py, which importsEventSerializer. The new direct import does not add a module to that path.Summary
Changes
propagate_attributesto serialize non-string metadata as compact JSON, leave strings unchanged, and skipNone.niklassemmlerexplicitly acknowledges that saved filters using old Python representations will not match newly encoded values. This stored-value change is intentional.Reviews (1) · Last reviewed commit: "fix(tracing): serialize non-string propa..." · Reviewed by Greptile