Skip to content

Fix double URL-encoding of context param in remote feature flags#177

Closed
corleymj wants to merge 1 commit into
mixpanel:masterfrom
corleymj:fix/remote-flags-double-url-encoding
Closed

Fix double URL-encoding of context param in remote feature flags#177
corleymj wants to merge 1 commit into
mixpanel:masterfrom
corleymj:fix/remote-flags-double-url-encoding

Conversation

@corleymj

@corleymj corleymj commented Jun 12, 2026

Copy link
Copy Markdown

Summary

RemoteFeatureFlagsProvider._prepare_query_params manually URL-encodes the JSON context string via urllib.parse.quote() before passing it as an httpx query parameter. Since httpx also URL-encodes all query parameter values when constructing the request URL, the context parameter ends up double-encoded:

Character Expected Actual (double-encoded)
{ %7B %257B
" %22 %2522
: %3A %253A

This causes the Mixpanel /flags API to return 400 Bad Request because it cannot parse the garbled context.

Before (broken)

context_json = json.dumps(context).encode("utf-8")
url_encoded_context = urllib.parse.quote(context_json)
params["context"] = url_encoded_context
# httpx then encodes again → %257B%2522distinct_id%2522...

After (fixed)

params["context"] = json.dumps(context)
# httpx handles encoding once → %7B%22distinct_id%22...

Changes

  • mixpanel/flags/remote_feature_flags.py: Remove manual urllib.parse.quote() and .encode("utf-8") in _prepare_query_params. Pass the raw JSON string and let httpx handle URL encoding.
  • mixpanel/flags/test_remote_feature_flags.py: Add TestPrepareQueryParams test class covering:
    • Context value is a plain JSON string (not pre-encoded)
    • Context value is str, not bytes
    • flag_key presence/absence
    • End-to-end check that the request URL is not double-encoded

Test plan

  • All 31 existing + new tests pass (pytest mixpanel/flags/test_remote_feature_flags.py)
  • New test_request_url_has_properly_encoded_context asserts no %257B (double-encode) or b%27 (bytes literal) in the outgoing URL
  • Verified against live Mixpanel /flags API — 400s resolve with this fix applied

Made with Cursor

The `_prepare_query_params` method was manually URL-encoding the JSON
context string via `urllib.parse.quote()` before passing it as an httpx
query parameter. Since httpx also URL-encodes all query parameter values,
the context was double-encoded — e.g. `{` became `%257B` instead of
`%7B` — causing the Mixpanel `/flags` API to return 400 Bad Request.

The fix passes the raw JSON string directly and lets httpx handle the
single layer of URL encoding as intended.

Co-authored-by: Cursor <cursoragent@cursor.com>
@corleymj corleymj requested review from a team and ketanmixpanel June 12, 2026 06:38
@lajohn4747

Copy link
Copy Markdown
Contributor

Nice I found the same issue in #175

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.58%. Comparing base (58d9c38) to head (d341dbe).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #177      +/-   ##
==========================================
+ Coverage   94.50%   94.58%   +0.07%     
==========================================
  Files          12       12              
  Lines        1947     1975      +28     
  Branches      116      116              
==========================================
+ Hits         1840     1868      +28     
  Misses         70       70              
  Partials       37       37              
Flag Coverage Δ
openfeature-provider 53.82% <0.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

lajohn4747 added a commit that referenced this pull request Jun 17, 2026
* Add Service Account support

* Fix lint

* refactor: use generic credentials parameter with type alias

- Rename service_account parameter to credentials for extensibility
- Add MixpanelCredentials type alias (Union[ServiceAccountCredentials])
- Keep ServiceAccountCredentials as standalone class (no base class)
- Update Mixpanel, Consumer, and BufferedConsumer signatures
- Update all tests, README, and CHANGELOG

Benefits:
- Generic parameter name supports future credential types
- Type alias is single source of truth for supported types
- Easy to extend: just add to Union when adding OAuth, API keys, etc.
- Self-documenting via IDE type hints

* refactor: move credentials to separate module

- Create mixpanel/credentials.py for authentication classes
- Move ServiceAccountCredentials and MixpanelCredentials to new file
- Import from credentials module in __init__.py
- Improves code organization and separation of concerns

Benefits:
- Cleaner module structure
- Easier to add new credential types in one place
- Credentials logic isolated from core tracking code

* feat: add APISecretCredentials class

- Add APISecretCredentials for API secret authentication
- Mark as deprecated in favor of ServiceAccountCredentials
- Update MixpanelCredentials type alias to Union of both types
- Add 4 new tests for API secret credentials

Benefits:
- Consistent credentials pattern for all auth types
- Explicit deprecation path from API secrets to service accounts
- Type-safe: validation at construction time
- All auth methods now use credentials classes

* Clean up by hannd

* Clean up

* Pass creds into feature flags

* Use httpx for flags

* Update to avoid credentials for custom consumers and flags

* Fix consumer

* Update

* Fix changelog

* Add comments

* Update change log

* Remove credentials

* Fix readme

* Use credentials for feature flag and fix encoding

* Ensure we don't fallback on token

* Update tests

* Don't need api_key

* Update deprecation methods

* Add logging to api_key too

* Comments handled

* Handle Greptile comments

* Update comment

* Fix greptile  nits

* Remove imports

* Clean up readme and tests

* Pass credentials into Consumer

* Update documentation

* Clear up tests

* Add warnings

* Fix comments

* remove dead var

* Fix lint

* Fix lint

* Handle lint errros

* add the encoding tests from PR #177

* Keep project token for flags

---------

Co-authored-by: John La <10409759+lajohn4747@users.noreply.github.com>
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.

4 participants