Skip to content

feat(flags): add get_remote_config_payload - #252

Open
ioannisj wants to merge 5 commits into
mainfrom
feat/get-remote-config-payload
Open

ioannisj wants to merge 5 commits into
mainfrom
feat/get-remote-config-payload

Conversation

@ioannisj

@ioannisj ioannisj commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Part of PostHog/posthog-android#577

The SDK can't read the payload of a remote config feature flag. This adds a public function, PostHog.FeatureFlags.get_remote_config_payload/2, which fetches it from GET /api/projects/@current/feature_flags/{key}/remote_config with the existing secret_key option.

  • Returns {:ok, payload} with the decoded JSON value. The endpoint sends the payload as a JSON string, so a string result is parsed a second time and stays a string if that parse fails.
  • Returns {:ok, nil} when the flag has no payload. PostHog answers that with a 200 and an empty body, so an empty or whitespace-only 2xx body isn't an error.
  • Returns {:ok, nil} without a request when the instance is disabled.
  • Returns {:error, exception} when secret_key is missing, the flag key is "", ., or .., the status isn't 2xx, the body isn't JSON, or the request fails.
  • Percent-encodes the flag key as one path segment, so a key with /, ?, or # can't change the request.
  • Makes one request per call, with no retry, no cache, and no $feature_flag_called event.

Three things differ from posthog-node:

  • A non-2xx status is an error here. posthog-node returns the error body as the payload.
  • The flag key is encoded. posthog-node sends it as is.
  • An empty 2xx body returns {:ok, nil}. posthog-node throws a SyntaxError on that response today, from await response.json() at packages/node/src/client.ts:2272 (480395c4).

With the default client, the request turns off Req's body decoding and the SDK parses the body itself. With Req's decoding, a 200 with a non-JSON content type (an HTML page from a proxy, for example) comes back as a plain string, and that looks the same as a decoded JSON string payload.

A custom api_client_module returns a decoded body, so the SDK doesn't decode the response again there and only parses the stored payload string. Both clients give the same result for the same payload, but with a custom client the SDK can't tell that a body wasn't JSON.

A Finch pool checkout timeout, which Finch raises, comes back as {:error, exception} like any other failed request.

💚 How did you test it?

Unit tests in test/posthog/feature_flags/remote_config_payload_test.exs and test/posthog/api/client_test.exs cover the request (path, encoded key, token param, bearer header, one request on a 503), the payload parsing, the empty and whitespace-only 200 bodies, and each error case (a 404 with an empty body and a pool checkout timeout included). The payload cases run against both the default client and a custom client that decodes the body.

mix test, mix format --check-formatted, mix credo --strict, and mix posthog.public_api --check pass. I didn't test against a live PostHog project.

📝 Checklist

  • All commits are signed (see Commit signing)
  • 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

DRI: @ioannisj
Autonomy: Human-driven (agent-assisted)

@ioannisj ioannisj self-assigned this Nov 13, 2026
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

posthog-elixir Compliance Report

Date: 2026-11-13T20:57:06.242395+00:00
Duration: 108382ms

⚠️ Some Tests Failed

40/47 tests passed, 7 failed


Capture Tests

⚠️ 29/30 tests passed, 1 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 606ms
Format Validation.Event Has Uuid ✅ 608ms
Format Validation.Event Has Lib Properties ✅ 607ms
Format Validation.Distinct Id Is String ✅ 606ms
Format Validation.Token Is Present ✅ 607ms
Format Validation.Custom Properties Preserved ✅ 607ms
Format Validation.Event Has Timestamp ✅ 607ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ❌ 607ms
Retry Behavior.Retries On 503 ✅ 5613ms
Retry Behavior.Does Not Retry On 400 ✅ 2611ms
Retry Behavior.Does Not Retry On 401 ✅ 2610ms
Retry Behavior.Respects Retry After Header ✅ 5612ms
Retry Behavior.Implements Backoff ✅ 15615ms
Retry Behavior.Retries On 500 ✅ 5614ms
Retry Behavior.Retries On 502 ✅ 5614ms
Retry Behavior.Retries On 504 ✅ 5614ms
Retry Behavior.Max Retries Respected ✅ 15623ms
Deduplication.Generates Unique Uuids ✅ 616ms
Deduplication.Preserves Uuid On Retry ✅ 5615ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10617ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5614ms
Deduplication.No Duplicate Events In Batch ✅ 611ms
Deduplication.Different Events Have Different Uuids ✅ 609ms
Compression.Sends Gzip When Enabled ✅ 607ms
Batch Format.Uses Proper Batch Structure ✅ 608ms
Batch Format.Flush With No Events Sends Nothing ✅ 605ms
Batch Format.Multiple Events Batched Together ✅ 611ms
Error Handling.Does Not Retry On 403 ✅ 2609ms
Error Handling.Does Not Retry On 413 ✅ 2609ms
Error Handling.Retries On 408 ✅ 5612ms

Failures

format_validation.non_utc_event_timestamp_is_converted_to_utc

Event 0 field 'timestamp' instant '2026-11-13T20:55:22.266799Z' != expected '2025-01-02T03:04:05Z'

Feature_Flags Tests

⚠️ 11/17 tests passed, 6 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 6ms
Request Payload.Flags Request Uses V2 Query Param ✅ 4ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 5ms
Request Payload.Flags Request Omits Authorization Header ✅ 4ms
Request Payload.Token In Flags Body Matches Init ✅ 5ms
Request Payload.Groups Round Trip ✅ 4ms
Request Payload.Groups Default To Empty Object ❌ 5ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 4ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 4ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 4ms
Request Lifecycle.No Flags Request On Init Alone ✅ 2ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 610ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 17ms
Request Lifecycle.Mock Response Value Is Returned To Caller ❌ 4ms
Retry Behavior.Retries Flags On 502 ❌ 308ms
Retry Behavior.Retries Flags On 504 ❌ 308ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ❌ 607ms

Failures

request_payload.groups_default_to_empty_object

Field 'groups' not found in /flags request body at path 'groups'. Available keys: ['distinct_id', 'api_key', 'flag_keys_to_evaluate']

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'api_key', 'flag_keys_to_evaluate']

request_lifecycle.mock_response_value_is_returned_to_caller

Last action result missing field 'value'. Keys: ['error', 'success']

retry_behavior.retries_flags_on_502

Last action result missing field 'value'. Keys: ['error', 'success']

retry_behavior.retries_flags_on_504

Last action result missing field 'value'. Keys: ['error', 'success']

side_effect_events.get_feature_flag_captures_feature_flag_called_event

Expected 1 events with name '$feature_flag_called', got 0

@posthog posthog Bot added the self-driving label Nov 13, 2026
@posthog

posthog Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

PostHog Review · Deep · reviewed 9479f5e

Posted 3 findings: 1 Should fix, 2 Consider.

Step Status Result
Prepare the diff done 4 files, 1 chunk
Pick perspectives done 3 perspectives
Run review passes done 6 issues (+1 blind-spot)
Merge overlapping findings done 7 → 5
Validate findings done 3 kept, 2 dismissed
Publish done 3 posted (view review)

@posthog posthog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this review and its findings in PostHog Review.

Comment thread lib/posthog/feature_flags.ex Resolved
Comment thread lib/posthog/api.ex Resolved
Comment thread lib/posthog/feature_flags.ex Resolved
@ioannisj
ioannisj marked this pull request as ready for review November 13, 2026 14:23
@ioannisj
ioannisj requested a review from a team as a code owner November 13, 2026 14:23
@veria-ai

veria-ai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

PR overview

No security issues were found in this pull request.

Reviews

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant