Skip to content

fix: drop the Anthropic SDK's URL query with capture_content off - #234

Merged
PabloPardoGarcia merged 4 commits into
mainfrom
pablo/rius-1620-anthropic-url-query
Oct 23, 2026
Merged

PabloPardoGarcia merged 4 commits into
mainfrom
pablo/rius-1620-anthropic-url-query

Conversation

@PabloPardoGarcia

@PabloPardoGarcia PabloPardoGarcia commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

In its content mode (ANTHROPIC_OPEN_TELEMETRY_TRACES_CONTENT_MODE=content), anthropic 2.1.0 writes the call's query to url.query and url.full on its own API-call spans, including the query parameters it treats as content, such as email or path_prefix. With capture_content=False these were exported in clear.

The masking exporter now treats url.query and url.full as content on spans whose instrumentation scope starts with com.anthropic.sdk., and on no other spans:

  • with capture_content=False, url.query is dropped and url.full keeps only its scheme, host and path (no query, fragment or userinfo). If it isn't a string or nothing is left, it is dropped;
  • with a mask, both go through it with their key, using the same extra-content-keys path that exception events use.

The keys come from opentelemetry.semconv.attributes.url_attributes, re-exported from rius.semconv like HTTP_RESPONSE_STATUS_CODE. The scope check reuses _native_spans.is_sdk_span.

Tests:

  • Shared cases from rius-semconv's masking.json, which gains an optional scope that test_sdk_cases.py now applies.
  • End to end, anthropic_native_span_run.py gains a memories_list case: beta.memory_stores.memories.list(path_prefix=...) against the local server, which now answers GET with an empty page. With capture off, the native span has no url.query, url.full ends at the path, and the prefix appears nowhere. A control with capture on shows that the SDK does write the query.
  • Fail before, pass after: without the masking.py change, three shared cases and the end-to-end capture-off test fail (the SDK's url.full was ...memories?path_prefix=%2Fsecret-path-prefix%2F). The second commit's new shared cases (userinfo, ?only=query) also failed before its change. With the changes, the full suite passes.

Pinned to rius-semconv v1.9.2: the vendored module (its only change is the comment on anthropic.tool_result.content) and tests/fixtures/semconv (SOURCE is the v1.9.2 commit, ebb29c2).

A later commit hardens how userinfo is handled. Userinfo is removed before the query and fragment are cut. url.full is dropped when the host and the credentials can't be told apart: there's an @ but no ://, an @ before ://, or an authority (up to the first /) that has both an @ and a ? or #. The new shared cases failed before that commit (6 of them) and pass after it. Python and TypeScript return the same url.full for 20,034 generated inputs, and no kept value has an @ outside its path.

In its content mode the anthropic SDK writes url.query and url.full with
query parameters it treats as content, such as an email or path_prefix
filter. On a span whose instrumentation scope starts with
com.anthropic.sdk., the masking exporter now treats both as content: with
capture_content off url.query is dropped and url.full keeps only its
scheme, host and path; with a mask both run through it. Other spans' URLs
are left alone.
…ntent off

Drop url.full when it is not a string or nothing is left of it, matching
the shared cases.
…old apart

Strip userinfo before the query cut, and drop a url.full with an @ but no
://, an @ before it, or an authority with both an @ and a ? or #.
@PabloPardoGarcia
PabloPardoGarcia marked this pull request as ready for review October 23, 2026 12:25
@PabloPardoGarcia
PabloPardoGarcia merged commit 676bae1 into main Oct 23, 2026
14 checks passed
@PabloPardoGarcia
PabloPardoGarcia deleted the pablo/rius-1620-anthropic-url-query branch October 23, 2026 12:25
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.

1 participant