fix(analytics): reject unresolvable gtePercentile filters on queryAnalytics - #4479
Draft
geclos wants to merge 1 commit into
Draft
fix(analytics): reject unresolvable gtePercentile filters on queryAnalytics#4479geclos wants to merge 1 commit into
geclos wants to merge 1 commit into
Conversation
…lytics The trace/session/scores/behaviors/moments streams of queryAnalytics accepted gtePercentile on any filter field, but only duration/ttft/cost are ever resolved into absolute thresholds (traces/sessions) or supported at all (scores/behaviors/moments). Any other field reached the ClickHouse filter builder unresolved and threw a plain Error, surfacing as an unhandled 500 instead of a validation 400 — the same class of bug already fixed for querySpans/analytics stream:"spans" filters (#3839) and the traces stream elsewhere (#4086), but never applied to queryAnalytics's own schema. Adds sessionFilterSetSchema (mirroring traceFilterSetSchema) and a rejectGtePercentileFilterSetSchema factory for the streams with no percentile-resolution step, and wires each queryAnalytics stream variant to the schema matching its actual filter builder instead of the generic filterSetSchema. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PoYZKJTkZD8NVBhpYkYfi1
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes an unhandled 500 in
queryAnalytics(POST /v1/projects/:projectSlug/analytics/query) when a caller sends agtePercentilefilter on a field the stream can't resolve it for.Datadog issue addressed:
bb657964-773c-11f1-b715-da7ad0900005—Error: Unsupported filter operator: gtePercentile(api,packages/platform/db-clickhouse/src/filter-builder.ts:201). Regressed on 2026-08-18 after a prior fix (#3839) had resolved a different call site; over the last 7 days this fired fromPOST /v1/projects/:projectSlug/analytics/query(stream: "sessions") viabuildSessionFilterClauses(session-repository.ts:376).Root cause:
gtePercentileis only meaningful when the filter builder resolves it into an absolute threshold first:traces/sessionsstreams resolve it, but only forduration/ttft/cost(resolvePercentileFilters) — any other field falls through unresolved.scores/behaviors/momentsstreams never resolve it at all.Either way, an unresolved
gtePercentilereachesbuildClauseinfilter-builder.ts, which throws a plainError("Unsupported filter operator: gtePercentile")— an unhandled 500 instead of a 400.This exact class of bug was already fixed for
querySpans/analyticsstream: "spans"(#3839,spanRowFilterSetSchema) and for thetracesdomain elsewhere (#4086,traceFilterSetSchema) — butqueryAnalytics's own schema (analyticsQuerySchemainpackages/domain/shared/src/analytics-query.ts) never adopted either hardened schema. All non-span streams shared one permissivefilterSetSchemaforfilters, so the gap silently generalized tosessions(the one that fired in production), plustraces,scores,behaviors, andmoments.Fix:
packages/domain/shared/src/filter.ts: addsessionFilterSetSchema(mirrorstraceFilterSetSchema, restrictinggtePercentiletoduration/ttft/cost) and arejectGtePercentileFilterSetSchema(streamLabel)factory for streams with no percentile-resolution step at all.packages/domain/shared/src/analytics-query.ts: give each stream variant ofanalyticsQuerySchemaits ownfiltersschema matching what its filter builder actually supports (traceFilterSetSchemafortraces,sessionFilterSetSchemaforsessions, existingspanRowFilterSetSchemaforspans,rejectGtePercentileFilterSetSchemaforscores/behaviors/moments) instead of one shared permissive schema.Handler-side,
packages/operations/src/operations/analytics.tsalready re-validates the request body throughanalyticsQuerySchemabefore it reaches the filter builder, so this alone is enough to turn the crash into a clean400— no handler changes needed.Related issue (if applicable)
N/A — found via Datadog Error Tracking triage, not a filed issue.
How was this tested?
Added regression tests to
packages/domain/shared/src/analytics-query.test.ts:gtePercentileonduration/ttft/coststill succeeds fortracesandsessions.gtePercentileon a non-percentile-eligible field (e.g.tokensInput) is now rejected fortracesandsessions.gtePercentileon any field is now rejected forscores,behaviors, andmoments.Confirmed the new tests fail without the fix (reproducing the exact unhandled-500 codepath) by temporarily stashing the
filter.ts/analytics-query.tschanges and re-running — both new assertions failed as expected — then restored the fix and re-ran to green.Verification in production: after deploy, occurrences of Datadog issue
bb657964-773c-11f1-b715-da7ad0900005should stop (any furthergtePercentilemisuse on these streams now returns a400from thequeryAnalyticshandler instead of a500).Remaining risk: the OpenAPI/SDK-facing mirror schema (
AnalyticsQueryBodySchemainpackages/operations/src/openapi/entities/analytics.ts) still documentsfilterswith the generic, unrestricted shape forsessions/scores/behaviors/moments— its code comment notes it's a Fern-generator-friendly mirror and that "domain filter constraints are re-checked in the handler via the domain schema," which this PR relies on. The runtime behavior is now correct (400 instead of 500), but SDK-generated types/docs for these streams don't yet reflect thegtePercentilerestriction. Left out of this PR to keep the fix minimal and low-risk; flagging as a good follow-up for API-docs accuracy.Checklist
Generated by Claude Code