Skip to content

feat: exception level, keyword-only request args, uuid and geoip fixes - #1046

Open
eli-r-ph wants to merge 6 commits into
v1-sync-mainfrom
v1-capture-api-fixes
Open

eli-r-ph wants to merge 6 commits into
v1-sync-mainfrom
v1-capture-api-fixes

Conversation

@eli-r-ph

@eli-r-ph eli-r-ph commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Five fixes for the 8.0 major, one commit each:

  • Keyword-only request.post and request.flags arguments. Removing gzip shifted the parameters after it. A 7.x call such as post(key, host, path, True) then set timeout=True (1 second) with no error. The parameters after path (post) and after host (flags) are now keyword-only, so such a call raises TypeError.
  • capture_exception(level=...) and reserved exception properties. 8.0 is the major that feat(error-tracking): standardize exception event metadata #898's deprecation promised.
    • Caller properties can no longer override the 14 reserved exception properties; clashing keys are dropped.
    • A new level= keyword on Client, AsyncPosthog and the module function sets $exception_level. It is normalized like integration levels, and an unknown value falls back to error. An integration's level wins over level=.
    • AsyncPosthog.capture_exception now sends $exception_level, which it never did before.
    • This matches the exception-event-metadata spec in sdk-specs and posthog-rs's .level().
    • Edge case: only per-call properties are checked. A reserved key in context tags or super_properties still fills in when the call leaves it unset.
  • Warn when a non-string $session_id or $window_id is dropped. It logs one warning per drop, naming the key and the JSON type, never the value. None stays silent and "" is still sent. This matches posthog-go and posthog-rs.
  • Invalid event uuid: one warning that never includes the value. An invalid caller uuid is still replaced with a generated UUIDv7. Before, the SDK logged this at error level with the caller's value in the message, and callers can put their own data in that field. It now logs one warning that names the rule only. A missing or empty uuid is generated silently, as a service, so uuid="" no longer logs. Client and AsyncPosthog now share one helper for this instead of two copies.
  • A per-call disable_geoip is a value of that event. Before, the call argument fell back to the client setting and sat below context tags and super_properties, and disable_geoip=False sent nothing. Now an explicit disable_geoip=True or False fills $geoip_disable above context tags and super_properties. A $geoip_disable in the call's own properties still wins over it. False is sent as $geoip_disable: false, so one call can turn GeoIP lookup back on when a context tag or super_properties turns it off. The client's disable_geoip setting keeps its place below every caller value.

The migration guide and five changesets cover all of them.

💚 How did you test it?

  • New and updated unit tests:
    • Reserved keys are ignored, on sync and async.
    • Level resolution, as a parameterized test.
    • Module forwarding of level.
    • The session id warning text per type, plus a silent None and an "" that is sent.
    • Invalid uuid values (string and non-string) log exactly one warning without the value, on sync and async; empty and missing uuid log nothing.
    • A parameterized precedence table for the per-call disable_geoip: call beats context, call beats super_properties, False beats super_properties and the client setting, and an event property beats the call. It runs on sync and async.
  • The new uuid and GeoIP tests fail against the previous commit's source and pass on this one.
  • ruff format --check, ruff check, mypy with the baseline filter, make public_api_check, and pytest --timeout=30 (4603 passed) all pass. Each commit passes make public_api_check on its own.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran sampo add to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Written with Cursor (Claude Opus 5.5). The reviewer decided the behavior: keyword-only arguments, the option A enforcement of exception metadata, a warning on every session id drop with None silent, the uuid rule (replace an invalid value with a warning, generate a missing or empty one silently), and the per-call disable_geoip precedence with an explicit false on the wire. The agent implemented it and checked it against the 7.x code on main and against posthog-go and posthog-rs.

A related change, making the AI integrations require capture_ai on a custom client, is stacked on this one in #1048 to keep this PR focused.

@eli-r-ph eli-r-ph self-assigned this Oct 10, 2026
@eli-r-ph
eli-r-ph marked this pull request as ready for review October 10, 2026 17:11
@eli-r-ph
eli-r-ph requested a review from a team as a code owner October 10, 2026 17:11
@eli-r-ph eli-r-ph changed the title feat: exception level, keyword-only request args and session id warning feat: exception level, keyword-only request args, uuid and geoip fixes Oct 10, 2026
An invalid caller uuid is still replaced with a generated UUIDv7, but the
SDK now logs one warning that names the rule instead of an error that
echoes the value. An empty string counts as unset and gets a generated
uuid without a log. Client and AsyncClient share one helper.
A disable_geoip argument now fills $geoip_disable as the event's own
value: above context tags, super_properties and the client setting, and
below a $geoip_disable in the call's properties. disable_geoip=False now
sends $geoip_disable: false. Client and AsyncClient share the layer in
_build_event_defaults.

This branch has not been deployed

No deployments
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