Uh oh!
There was an error while loading. Please reload this page.
fix(posthog): validate integration against live API docs, add self-hosted support + CRUD coverage - #5476
Conversation
…sted support + CRUD coverage Fix missing response.ok checks across ~36 tools that silently treated error bodies as success. Fix delete_feature_flag ignoring failure responses, evaluate_flags targeting the undocumented /decide endpoint without the required api_key body field, and batch_events reporting a hardcoded events_processed count. Add self-hosted host support (utils.ts) alongside the existing US/EU region selector, and complete CRUD coverage with 5 new tools: update_insight, update_cohort, update_experiment, delete_survey, create_dashboard.
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Adds update insight/cohort/experiment, create dashboard, and delete survey operations, with matching block fields (e.g. favorited, pinned, archive cohort/experiment). Aligns several tools with documented PostHog behavior: feature flag delete is a soft-delete PATCH; person delete uses bulk_delete; evaluate flags calls Reviewed by Cursor Bugbot for commit 98d6feb. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Greptile SummaryThis PR hardens the PostHog integration in three areas: fixes ~36 tools that were silently treating error responses as success data, migrates
Confidence Score: 5/5Safe to merge — the fixes are well-scoped and the endpoint migration is validated against live PostHog docs. The core changes (removing incorrect response.ok guards, the evaluate_flags endpoint migration, and the new CRUD tools) are all correct. The SSRF guard for self-hosted hosts is already in place via validateExternalUrl. The two findings are minor: a redundant JSON.parse in batch_events that cannot cause a runtime failure, and a silent-swallow in create_insight that predates this PR but was not corrected alongside its new peer update_insight. Neither affects the correctness of the new tools or the fixes. apps/sim/tools/posthog/create_insight.ts — silent JSON parse fallback to null is inconsistent with every other tool in this PR and could confuse users creating insights with malformed query JSON. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Tool invoked] --> B{host param set?}
B -- Yes --> C[normalizeHost]
C --> D[validateExternalUrl / SSRF guard]
D -- Invalid --> E[throw Error]
D -- Valid --> F[Custom host URL]
B -- No --> G{region?}
G -- eu --> H[eu.posthog.com / eu.i.posthog.com]
G -- us/default --> I[us.posthog.com / us.i.posthog.com]
F --> J[HTTP request]
H --> J
I --> J
J --> K{Non-2xx?}
K -- Yes --> L[Framework throws before transformResponse]
K -- No --> M[transformResponse]
M --> N{Ingest tool? capture/batch/flags}
N -- Yes --> O[Check data.status === 1]
N -- No --> P[Parse API response JSON]
O --> Q[Return success/failure]
P --> Q
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Tool invoked] --> B{host param set?}
B -- Yes --> C[normalizeHost]
C --> D[validateExternalUrl / SSRF guard]
D -- Invalid --> E[throw Error]
D -- Valid --> F[Custom host URL]
B -- No --> G{region?}
G -- eu --> H[eu.posthog.com / eu.i.posthog.com]
G -- us/default --> I[us.posthog.com / us.i.posthog.com]
F --> J[HTTP request]
H --> J
I --> J
J --> K{Non-2xx?}
K -- Yes --> L[Framework throws before transformResponse]
K -- No --> M[transformResponse]
M --> N{Ingest tool? capture/batch/flags}
N -- Yes --> O[Check data.status === 1]
N -- No --> P[Parse API response JSON]
O --> Q[Return success/failure]
P --> Q
Reviews (5): Last reviewed commit: "fix(posthog): fix cross-field value leak..." | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…t bugs
The prior commit added if (!response.ok) branches inside transformResponse
across ~40 tool files. This is dead code — tools/index.ts already throws
on non-2xx (and error-payload) responses before transformResponse is ever
invoked, so transformResponse only ever receives already-successful
responses. Reverted to the idiomatic no-error-branch pattern used
elsewhere in the codebase (e.g. hunter/email_verifier.ts), and added a
posthog-errors errorExtractor so the framework's own error throw surfaces
PostHog's real {type, code, detail, attr} error shape instead of a
generic status message.
Verified against PostHog's live OpenAPI schema, fixed real bugs:
- delete_feature_flag: DELETE always returns 405 (hard delete not
allowed); switched to PATCH with deleted: true
- delete_person: no single-person DELETE endpoint exists; switched to
POST .../persons/bulk_delete/ with ids: [personId]
- create_annotation: insight_short_id is read-only on create; the
writable field is dashboard_id
- removed nonexistent fields (experiment variants, insight
filters/saved) not present in the current schema
- added missing trailing slashes on feature-flag/experiment URLsThe self-hosted host field accepted any string and only stripped trailing slashes before prepending https://, so a workflow could point it at loopback/private/link-local addresses (e.g. cloud instance- metadata endpoints) and the executor would make a real server-side request to it. Reuse the shared validateExternalUrl SSRF guard, same pattern already used for Convex's custom deployment URL (tools/convex/utils.ts); the tool executor separately re-validates with DNS resolution and pins the resolved IP for the actual request. Also drop an unused params arg in evaluate_flags' headers function.
waleedlatif1
commented
Jul 7, 2026
@greptile review |
waleedlatif1
commented
Jul 7, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ON params
Several tools caught JSON.parse failures on user-supplied filter/query/
parameters strings and silently substituted {} or null, which would
wipe the corresponding field on the PATCH/create request instead of
surfacing an error (Cursor Bugbot flagged this for update_cohort,
update_experiment, update_insight; the same pattern existed in their
create_* / update_feature_flag / evaluate_flags counterparts, fixed for
consistency). Now throws a descriptive error, matching the existing
convention in tools/notion/query_database.ts.
Also fixes batch_events: the request body silently sent an empty batch
on invalid JSON, and transformResponse always reported "captured
successfully" even when PostHog's response indicated failure
(data.status !== 1).waleedlatif1
commented
Jul 7, 2026
@greptile review |
waleedlatif1
commented
Jul 7, 2026
@cursor review |
posthog_update_experiment was the only experiment operation missing from the region field's required-condition list; the other three (create/get/list) already require it. Region is unconditionally visible on this block (no condition key gates it), so this was a required-ness inconsistency rather than a functional bug, but users updating an EU experiment should still be prompted to select the region explicitly rather than relying on the default.
waleedlatif1
commented
Jul 7, 2026
Re: the region/update_experiment finding — clarifying and fixing. |
waleedlatif1
commented
Jul 7, 2026
@greptile review |
waleedlatif1
commented
Jul 7, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Merges update_insight's query subblock into the same insightQuery id
already used by create_insight (Cursor flagged: it previously reused
the 'query' subblock id shared by posthog_query's HogQL field and the
cohort query fields, so switching operations could carry a stale
HogQL/cohort-JSON value into an insight PATCH). Matches the existing
merged-condition pattern used elsewhere in this block instead of
duplicating the subblock id.
Also fixes two more false-success reports in the same class as the
batch_events/delete_feature_flag fixes: capture_event now checks the
ingest response's status field (same {"status": 1} contract as
/batch/) instead of unconditionally returning success, and
delete_person now reports failure when persons_deleted is 0 instead of
always success: true.waleedlatif1
commented
Jul 7, 2026
@greptile review |
waleedlatif1
commented
Jul 7, 2026
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 98d6feb. Configure here.
waleedlatif1
commented
Jul 7, 2026
Review loop complete — Greptile 5/5, Cursor Bugbot clean, 0 unresolved threads, all on latest commit (98d6feb). Summary of what changed across 6 commits:
Every finding across all rounds was independently verified against PostHog's live docs/OpenAPI schema or the actual framework code before fixing — 2 bot claims were disproven as false positives with doc citations, the rest were real and fixed. |
Summary
response.okchecks)delete_feature_flagreturningsuccess: trueregardless of actual API responseevaluate_flagstargeting the undocumented/decideendpoint and missing the requiredapi_keybody field; migrated to the documented/flags/?v=2endpointbatch_eventsreporting a fabricatedevents_processedcount instead of the actual batch sizeutils.ts) alongside the existing US/EU region selectorupdate_insight,update_cohort,update_experiment,delete_survey,create_dashboardType of Change
Testing
Validated every tool against PostHog's live API docs.
tsc --noEmitandbunx biome checkboth clean.Checklist