Skip to content

fix(scenes): strip trailing whitespace from route paths - #70440

Draft
posthog[bot] wants to merge 2 commits into
masterfrom
posthog-code/fix-scene-route-trailing-whitespace
Draft

fix(scenes): strip trailing whitespace from route paths#70440
posthog[bot] wants to merge 2 commits into
masterfrom
posthog-code/fix-scene-route-trailing-whitespace

Conversation

@posthog

@posthog posthog Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Problem

Error Tracking keeps recording Error: argument must not contain whitespace from sceneLogic, 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. surveyLogic builds its urlToAction key 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, so new UrlPattern('/project/.../surveys/<uuid> ') throws. PersonScene avoids this because it keys on a static /person/* wildcard rather than interpolating the param. The prior fix's guardRoute only wrapped sceneLogic's own handlers, so it never covered this other-logic mount path. The throw was already caught by setScene and 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 (pathFromWindowToRoutes in initKea), 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 into url-pattern.

Embedded whitespace is deliberately preserved — routes like /person/foo bar rely 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.3 with the reported survey id + trailing space, and confirmed the normalized path constructs cleanly.

Added a stripTrailingWhitespace unit test group in kea-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

  • Publish to changelog?
  • Alert Sales and Marketing teams?

🤖 Agent context

Autonomy: Fully autonomous

Investigated via PostHog Error Tracking MCP (query-error-tracking-issue-events) to pull the resolved stack trace, which pointed at url-pattern's constructor called from kea-router's urlToAction builder during surveyLogic mount — not at sceneLogic's own handlers that the previous fix wrapped. Skills invoked: /investigating-error-issue, /writing-tests.

Considered a survey-scoped fix (trim props.id in Survey.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.

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
@posthog posthog Bot added the skip-agent-review Save $$$, skip auto agent reviews (Greptile) — use for trivial or chore PRs label Jul 13, 2026
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +188.2 KiB (+0.3%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 64.52 MiB · 🔺 +188.2 KiB (+0.3%)

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%)

@trunk-io

trunk-io Bot commented Jul 13, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

…espace

Generated-By: PostHog Code
Task-Id: c1286560-5e83-4867-900b-98897ec4ee64
@scheduled-actions-posthog

Copy link
Copy Markdown
Contributor

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 stale label – otherwise this will be closed in another week. If you want to permanently keep it open, use the waiting label.

@trunk-io

trunk-io Bot commented Jul 28, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-agent-review Save $$$, skip auto agent reviews (Greptile) — use for trivial or chore PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants