fix(scenes): strip trailing whitespace from route paths - #70440
fix(scenes): strip trailing whitespace from route paths#70440posthog[bot] wants to merge 2 commits into
Conversation
A stray trailing space on a copy-pasted link (e.g. `/surveys/<id>%20`) decodes to a real space in the matched route param. Logics that build a route key from that param — `surveyLogic` keys on `urls.survey(props.id)` — then feed the whitespace into `url-pattern`, whose constructor throws `argument must not contain whitespace`. Strip trailing whitespace at the route-matching boundary so the route still resolves, while leaving embedded whitespace (distinct ids like `foo bar` in `/person/foo bar`) untouched. Generated-By: PostHog Code Task-Id: c1286560-5e83-4867-900b-98897ec4ee64
🤖 CI report
|
| File | Size | Δ vs base |
|---|---|---|
posthog-app/src/scenes/onboarding/Onboarding.js |
47.0 KiB | 🟢 -748.6 KiB (-94.1%) |
toolbar/src/toolbar/debug/chunk-EventDebugMenu.js |
255.9 KiB | 🔺 +237.4 KiB (+1281.6%) |
exporter/src/exporter/scenes/ExporterNotebookScene.js |
3.11 MiB | 🟢 -93.7 KiB (-2.9%) |
exporter/_parent/products/alerts/frontend/views/EditAlertModal.js |
94.6 KiB | 🔺 +93.2 KiB (+6532.0%) |
render-query/src/render-query/render-query.js |
21.29 MiB | 🔺 +90.4 KiB (+0.4%) |
exporter/src/queries/schema.js |
1.09 MiB | 🔺 +87.0 KiB (+8.4%) |
posthog-app/src/queries/schema.js |
1.09 MiB | 🔺 +87.0 KiB (+8.4%) |
posthog-app/src/scenes/quickstart/Quickstart.js |
78.0 KiB | 🔺 +78.0 KiB (new) |
posthog-app/_parent/products/review_hog/frontend/CodeReviewScene.js |
52.9 KiB | 🔺 +52.9 KiB (new) |
posthog-app/src/scenes/inbox/InboxScene.js |
677.8 KiB | 🔺 +28.5 KiB (+4.4%) |
posthog-app/src/scenes/feature-flags/FeatureFlagForm.js |
22.7 KiB | 🔺 +22.7 KiB (new) |
posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapNewScene.js |
28.0 KiB | 🔺 +22.2 KiB (+382.7%) |
posthog-app/src/scenes/feature-flags/FeatureFlag.js |
96.6 KiB | 🟢 -19.0 KiB (-16.5%) |
posthog-app/_parent/products/pulse/frontend/PulseScene.js |
17.5 KiB | 🔺 +17.5 KiB (new) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner.js |
96.9 KiB | 🔺 +14.8 KiB (+18.0%) |
posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapRecordingScene.js |
3.8 KiB | 🟢 -12.4 KiB (-76.3%) |
posthog-app/_parent/products/stamphog/frontend/scenes/StamphogScene/StamphogScene.js |
11.8 KiB | 🔺 +11.8 KiB (new) |
posthog-app/_parent/products/engineering_analytics/frontend/scenes/EngineeringAnalyticsScene.js |
70.3 KiB | 🔺 +11.6 KiB (+19.8%) |
posthog-app/_parent/products/alerts/frontend/views/InsightAlerts.js |
11.2 KiB | 🔺 +11.2 KiB (new) |
posthog-app/_parent/products/cohorts/frontend/staff/CohortsStaffToolsScene.js |
11.1 KiB | 🔺 +11.1 KiB (new) |
posthog-app/src/scenes/hog-functions/HogFunctionScene.js |
51.3 KiB | 🟢 -10.0 KiB (-16.3%) |
posthog-app/src/scenes/experiments/Experiment.js |
231.5 KiB | 🔺 +9.7 KiB (+4.4%) |
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/components/SidePanelRunnerImpl.js |
16.8 KiB | 🔺 +9.6 KiB (+134.9%) |
posthog-app/src/scenes/max/messages/adapters/SearchSessionRecordingsWidget.js |
removed | 🟢 -9.1 KiB (-100.0%) |
posthog-app/src/scenes/max/messages/adapters/ErrorTrackingWidget.js |
removed | 🟢 -9.0 KiB (-100.0%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/ErrorTrackingWidget.js |
9.0 KiB | 🔺 +9.0 KiB (new) |
posthog-app/_parent/products/logs/frontend/components/LogsViewer/LogsViewerModal/LogsViewerModal.js |
11.6 KiB | 🔺 +8.5 KiB (+268.4%) |
posthog-app/src/scenes/max/messages/adapters/CreateInsightWidget.js |
removed | 🟢 -8.4 KiB (-100.0%) |
posthog-app/src/scenes/max/messages/adapters/QueryWidget.js |
removed | 🟢 -8.4 KiB (-100.0%) |
posthog-app/_parent/products/posthog_ai/frontend/scenes/TaskTracker/TaskTracker.js |
27.0 KiB | 🔺 +8.3 KiB (+44.7%) |
posthog-app/_parent/products/engineering_analytics/frontend/scenes/EngineeringAnalyticsTeamScene.js |
8.2 KiB | 🔺 +8.2 KiB (new) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/QueryWidget.js |
8.0 KiB | 🔺 +8.0 KiB (new) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/CreateInsightWidget.js |
8.0 KiB | 🔺 +8.0 KiB (new) |
posthog-app/_parent/products/metrics/frontend/MetricsScene.js |
46.5 KiB | 🔺 +7.5 KiB (+19.4%) |
posthog-app/_parent/products/ai_observability/frontend/AIObservabilitySessionScene.js |
11.6 KiB | 🔺 +7.3 KiB (+170.3%) |
posthog-app/_parent/products/workflows/frontend/WorkflowsScene.js |
69.9 KiB | 🔺 +7.2 KiB (+11.6%) |
exporter/src/exporter/scenes/ExporterDashboardScene.js |
279.0 KiB | 🔺 +6.6 KiB (+2.4%) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ActionEditorScene.js |
22.1 KiB | 🔺 +6.3 KiB (+40.3%) |
posthog-app/_parent/products/workflows/frontend/Workflows/WorkflowScene.js |
125.8 KiB | 🔺 +6.2 KiB (+5.2%) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ScannerEditorScene.js |
23.6 KiB | 🟢 -6.1 KiB (-20.6%) |
posthog-app/_parent/products/logs/frontend/scenes/LogsAlertDetailScene/LogsAlertDetailScene.js |
25.5 KiB | 🔺 +6.0 KiB (+30.4%) |
posthog-app/src/scenes/bootApp.js |
5.4 KiB | 🔺 +5.4 KiB (new) |
posthog-app/src/scenes/App.js |
32.1 KiB | 🔺 +5.3 KiB (+19.8%) |
posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene.js |
140.4 KiB | 🟢 -5.3 KiB (-3.6%) |
posthog-app/_parent/products/feature_flags/frontend/staff/FeatureFlagsStaffToolsScene.js |
15.8 KiB | 🔺 +5.2 KiB (+49.0%) |
posthog-app/_parent/products/alerts/frontend/AlertsScene.js |
4.7 KiB | 🔺 +4.7 KiB (new) |
posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene.js |
124.9 KiB | 🔺 +4.5 KiB (+3.7%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/SearchSessionRecordingsWidget.js |
4.1 KiB | 🔺 +4.1 KiB (new) |
posthog-app/_parent/products/tracing/frontend/TracingOperationScene.js |
15.7 KiB | 🔺 +4.0 KiB (+33.6%) |
posthog-app/_parent/products/data_warehouse/frontend/scenes/SchemaScene/SchemaScene.js |
38.7 KiB | 🔺 +3.8 KiB (+10.8%) |
posthog-app/_parent/products/tracing/frontend/TracingScene.js |
86.1 KiB | 🟢 -3.8 KiB (-4.2%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/builtinToolRenderers.js |
9.5 KiB | 🔺 +3.6 KiB (+62.2%) |
posthog-app/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene.js |
45.2 KiB | 🔺 +3.5 KiB (+8.4%) |
posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingFingerprintScene/ErrorTrackingFingerprintScene.js |
3.3 KiB | 🔺 +3.3 KiB (new) |
posthog-app/_parent/products/ai_observability/frontend/AIObservabilityScene.js |
120.9 KiB | 🔺 +3.3 KiB (+2.8%) |
posthog-app/_parent/products/logs/frontend/components/LogsAlerting/LogsAlertingSection.js |
3.2 KiB | 🔺 +3.2 KiB (new) |
posthog-app/_parent/products/logs/frontend/LogsScene.js |
27.4 KiB | 🔺 +2.6 KiB (+10.4%) |
posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation.js |
58.2 KiB | 🟢 -2.3 KiB (-3.8%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/CreateNotebookWidget.js |
2.3 KiB | 🔺 +2.3 KiB (new) |
posthog-app/src/scenes/max/messages/adapters/CreateNotebookWidget.js |
removed | 🟢 -2.2 KiB (-100.0%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/EditDiffRenderer.js |
1.6 KiB | 🟢 -2.1 KiB (-57.8%) |
posthog-app/_parent/products/posthog_ai/frontend/components/tool/widgets/UpsertDashboardWidget.js |
2.0 KiB | 🔺 +2.0 KiB (new) |
posthog-app/src/scenes/max/messages/adapters/UpsertDashboardWidget.js |
removed | 🟢 -2.0 KiB (-100.0%) |
posthog-app/_parent/products/ai_observability/frontend/evaluations/EvaluationTemplates.js |
2.9 KiB | 🔺 +2.0 KiB (+216.3%) |
posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene.js |
104.5 KiB | 🔺 +1.9 KiB (+1.9%) |
exporter/src/exporter/scenes/ExporterInterviewScene.js |
304.6 KiB | 🔺 +1.7 KiB (+0.5%) |
posthog-app/src/scenes/max/Max.js |
23.9 KiB | 🔺 +1.6 KiB (+7.2%) |
posthog-app/src/scenes/AuthenticatedShell.js |
216.8 KiB | 🟢 -1.6 KiB (-0.7%) |
posthog-app/_parent/products/ai_observability/frontend/AIObservabilityTraceScene.js |
132.9 KiB | 🔺 +1.6 KiB (+1.2%) |
posthog-app/_parent/products/replay_vision/frontend/replay_scanners/VisionActionScene.js |
8.3 KiB | 🔺 +1.5 KiB (+22.6%) |
posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsToolDetail.js |
18.2 KiB | 🔺 +1.5 KiB (+9.2%) |
posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptScene.js |
41.0 KiB | 🔺 +1.5 KiB (+3.7%) |
posthog-app/src/scenes/session-recordings/player/modal/SessionPlayerModal.js |
11.0 KiB | 🔺 +1.5 KiB (+15.3%) |
posthog-app/src/scenes/data-pipelines/legacy-plugins/LegacyPluginScene.js |
20.9 KiB | 🟢 -1.3 KiB (-5.9%) |
exporter/src/scenes/insights/views/BoxPlot/BoxPlot.js |
3.2 KiB | 🟢 -1.2 KiB (-27.3%) |
posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapScene.js |
9.9 KiB | 🟢 -1.2 KiB (-10.8%) |
posthog-app/src/scenes/persons/PersonScene.js |
33.2 KiB | 🔺 +1.2 KiB (+3.7%) |
posthog-app/src/scenes/project-homepage/ProjectHomepage.js |
31.0 KiB | 🔺 +1.2 KiB (+4.0%) |
posthog-app/src/scenes/instance/QueryPerformance/QueryPerformance.js |
33.0 KiB | 🔺 +1.1 KiB (+3.4%) |
posthog-app/src/scenes/surveys/wizard/SurveyWizard.js |
68.6 KiB | 🟢 -1.1 KiB (-1.5%) |
exporter/src/lib/components/ActivityLog/describers.js |
128.2 KiB | 🔺 +1.0 KiB (+0.8%) |
posthog-app/src/scenes/data-management/definition/DefinitionView.js |
33.2 KiB | 🔺 +1023 B (+3.1%) |
posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingScene/ErrorTrackingScene.js |
46.4 KiB | 🔺 +1015 B (+2.2%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.24 MiB · 22 files | 🔺 +23.9 KiB (+1.9%) | ███░░░░░░░ 28.8% of 4.29 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.20 MiB · 3,001 files | 🔺 +92.7 KiB (+1.1%) | █████████░ 88.6% of 9.25 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 281.3 KiB | ../node_modules/.pnpm/posthog-js@1.405.2/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 235.8 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 224.4 KiB | ../node_modules/.pnpm/posthog-js@1.405.2/node_modules/posthog-js/dist/module.js |
| 167.1 KiB | src/queries/validators.js |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 106.0 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 93.2 KiB | ../packages/quill/packages/quill/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
⚠️ Dist folder size — 🔺 +70.93 MiB (+5.5%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1355.84 MiB · 🔺 +70.93 MiB (+5.5%)
…espace Generated-By: PostHog Code Task-Id: c1286560-5e83-4867-900b-98897ec4ee64
|
This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the |
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
Problem
Error Tracking keeps recording
Error: argument must not contain whitespacefromsceneLogic, even after #70254 guarded scene URL handling. That PR fixed the malformed-percent branch, but the whitespace branch survived.Root cause: a URL like
/surveys/<uuid>%20(a stray trailing space, typically from a copy-pasted link) decodes to a real trailing space in the matched route param.surveyLogicbuilds itsurlToActionkey dynamically from that param:https://github.com/PostHog/posthog/blob/master/frontend/src/scenes/surveys/surveyLogic.tsx#L3124-L3125
url-pattern's constructor rejects any whitespace in a pattern literal, sonew UrlPattern('/project/.../surveys/<uuid> ')throws.PersonSceneavoids this because it keys on a static/person/*wildcard rather than interpolating the param. The prior fix'sguardRouteonly wrappedsceneLogic's own handlers, so it never covered this other-logic mount path. The throw was already caught bysetSceneand routed to a 404 (so no user-facing crash), but it kept getting captured as noise.Changes
Strip trailing whitespace at the route-matching boundary (
pathFromWindowToRoutesininitKea), alongside the existing trailing-slash strip. A stray trailing space now normalizes away before route matching, so the survey route resolves and loads normally instead of feeding whitespace intourl-pattern.Embedded whitespace is deliberately preserved — routes like
/person/foo barrely on a space inside a distinct id, and no route pattern can ever end in whitespace anyway.Note
The reopened report suggested rendering a safe 404. Stripping the stray trailing space instead lets a valid survey with a copy-paste artifact just load, which is the better outcome. Either way the key requirement holds: routing no longer reaches
url-pattern's whitespace validation.How did you test this code?
I (Claude) reproduced the exact throw against
url-pattern@1.0.3with the reported survey id + trailing space, and confirmed the normalized path constructs cleanly.Added a
stripTrailingWhitespaceunit test group inkea-router.test.ts. It guards two regressions: dropping the trailing-whitespace strip (the survey crash returns) and over-correcting to strip all whitespace (which would break embedded-space distinct-id lookups like/person/foo bar).I could not run the Jest suite or typecheck in this environment (no
node_modules/flox), so those run in CI.Automatic notifications
🤖 Agent context
Autonomy: Fully autonomous
Investigated via PostHog Error Tracking MCP (
query-error-tracking-issue-events) to pull the resolved stack trace, which pointed aturl-pattern's constructor called from kea-router'surlToActionbuilder duringsurveyLogicmount — not atsceneLogic's own handlers that the previous fix wrapped. Skills invoked:/investigating-error-issue,/writing-tests.Considered a survey-scoped fix (trim
props.idinSurvey.tsx) but chose the router boundary since the same dynamic-key pattern exists in many scene logics, and a single normalization point covers them all without per-scene whack-a-mole.Created with PostHog Code from an inbox report.